PageRenderTime 72ms CodeModel.GetById 20ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/http/request.c

https://bitbucket.org/cesbo/astra
C | 1408 lines | 1046 code | 252 blank | 110 comment | 192 complexity | b5cf72be8c2047e981052f05b00ec9a4 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
   1/*
   2 * Astra Module: HTTP Request
   3 * http://cesbo.com/astra
   4 *
   5 * Copyright (C) 2012-2015, Andrey Dyldin <and@cesbo.com>
   6 *
   7 * This program is free software: you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation, either version 3 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21/*
  22 * Module Name:
  23 *      http_request
  24 *
  25 * Module Options:
  26 *      host        - string, server hostname or IP address
  27 *      port        - number, server port (default: 80)
  28 *      path        - string, request path
  29 *      method      - string, method (default: "GET")
  30 *      version     - string, HTTP version (default: "HTTP/1.1")
  31 *      headers     - table, list of the request headers
  32 *      content     - string, request content
  33 *      stream      - boolean, true to read MPEG-TS stream
  34 *      sync        - boolean or number, enable stream synchronization
  35 *      sctp        - boolean, use sctp instead of tcp
  36 *      timeout     - number, request timeout
  37 *      callback    - function,
  38 *      upstream    - object, stream instance returned by module_instance:stream()
  39 */
  40
  41#include "http.h"
  42
  43#define MSG(_msg)                                       \
  44    "[http_request %s:%d%s] " _msg, mod->config.host    \
  45                                  , mod->config.port    \
  46                                  , mod->config.path
  47
  48struct module_data_t
  49{
  50    MODULE_STREAM_DATA();
  51
  52    struct
  53    {
  54        const char *host;
  55        int port;
  56        const char *path;
  57        bool sync;
  58    } config;
  59
  60    int timeout_ms;
  61    bool is_stream;
  62
  63    int idx_self;
  64
  65    asc_socket_t *sock;
  66    asc_timer_t *timeout;
  67
  68    bool is_socket_busy;
  69
  70    // request
  71    struct
  72    {
  73        int status; // 1 - connected, 2 - request done
  74
  75        const char *buffer;
  76        size_t skip;
  77        size_t size;
  78
  79        int idx_body;
  80    } request;
  81
  82    bool is_head;
  83    bool is_connection_close;
  84    bool is_connection_keep_alive;
  85
  86    // response
  87    char buffer[HTTP_BUFFER_SIZE];
  88    size_t buffer_skip;
  89    size_t chunk_left;
  90
  91    int idx_response;
  92    int status_code;
  93
  94    int status;         // 1 - empty line is found, 2 - request ready, 3 - release
  95
  96    int idx_content;
  97    bool is_chunked;
  98    bool is_content_length;
  99    string_buffer_t *content;
 100
 101    bool is_active;
 102
 103    // receiver
 104    struct
 105    {
 106        void *arg;
 107        union
 108        {
 109            void (*fn)(void *, void *, size_t);
 110            void *ptr;
 111        } callback;
 112    } receiver;
 113
 114    // stream
 115    bool is_thread_started;
 116    asc_thread_t *thread;
 117    asc_thread_buffer_t *thread_output;
 118
 119    struct
 120    {
 121        uint8_t *buffer;
 122        size_t buffer_size;
 123        size_t buffer_count;
 124        size_t buffer_read;
 125        size_t buffer_write;
 126        size_t buffer_fill;
 127    } sync;
 128
 129    uint64_t pcr;
 130};
 131
 132static const char __path[] = "path";
 133static const char __method[] = "method";
 134static const char __version[] = "version";
 135static const char __headers[] = "headers";
 136static const char __content[] = "content";
 137static const char __callback[] = "callback";
 138static const char __stream[] = "stream";
 139static const char __code[] = "code";
 140static const char __message[] = "message";
 141
 142static const char __default_method[] = "GET";
 143static const char __default_path[] = "/";
 144static const char __default_version[] = "HTTP/1.1";
 145
 146static const char __connection[] = "Connection: ";
 147static const char __close[] = "close";
 148static const char __keep_alive[] = "keep-alive";
 149
 150static void on_close(void *);
 151
 152static void callback(module_data_t *mod)
 153{
 154    const int response = lua_gettop(lua);
 155    lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self);
 156    lua_getfield(lua, -1, "__options");
 157    lua_getfield(lua, -1, "callback");
 158    lua_pushvalue(lua, -3);
 159    lua_pushvalue(lua, response);
 160    lua_call(lua, 2, 0);
 161    lua_pop(lua, 3); // self + options + response
 162}
 163
 164static void call_error(module_data_t *mod, const char *msg)
 165{
 166    lua_newtable(lua);
 167    lua_pushnumber(lua, 0);
 168    lua_setfield(lua, -2, __code);
 169    lua_pushstring(lua, msg);
 170    lua_setfield(lua, -2, __message);
 171    callback(mod);
 172}
 173
 174void timeout_callback(void *arg)
 175{
 176    module_data_t *mod = (module_data_t *)arg;
 177
 178    asc_timer_destroy(mod->timeout);
 179    mod->timeout = NULL;
 180
 181    if(mod->request.status == 0)
 182    {
 183        mod->status = -1;
 184        mod->request.status = -1;
 185        call_error(mod, "connection timeout");
 186    }
 187    else
 188    {
 189        mod->status = -1;
 190        mod->request.status = -1;
 191        call_error(mod, "response timeout");
 192    }
 193
 194    on_close(mod);
 195}
 196
 197static void on_thread_close(void *arg);
 198
 199static void on_close(void *arg)
 200{
 201    module_data_t *mod = (module_data_t *)arg;
 202
 203    if(mod->thread)
 204        on_thread_close(mod);
 205
 206    if(!mod->sock)
 207        return;
 208
 209    if(mod->receiver.callback.ptr)
 210    {
 211        mod->receiver.callback.fn(mod->receiver.arg, NULL, 0);
 212
 213        mod->receiver.arg = NULL;
 214        mod->receiver.callback.ptr = NULL;
 215    }
 216
 217    asc_socket_close(mod->sock);
 218    mod->sock = NULL;
 219
 220    if(mod->timeout)
 221    {
 222        asc_timer_destroy(mod->timeout);
 223        mod->timeout = NULL;
 224    }
 225
 226    if(mod->request.buffer)
 227    {
 228        if(mod->request.status == 1)
 229            free((void *)mod->request.buffer);
 230        mod->request.buffer = NULL;
 231    }
 232
 233    if(mod->request.idx_body)
 234    {
 235        luaL_unref(lua, LUA_REGISTRYINDEX, mod->request.idx_body);
 236        mod->request.idx_body = 0;
 237    }
 238
 239    if(mod->request.status == 0)
 240    {
 241        mod->request.status = -1;
 242        call_error(mod, "connection failed");
 243    }
 244    else if(mod->status == 0)
 245    {
 246        mod->request.status = -1;
 247        call_error(mod, "failed to parse response");
 248    }
 249
 250    if(mod->status == 2)
 251    {
 252        mod->status = 3;
 253
 254        lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_response);
 255        callback(mod);
 256    }
 257
 258    if(mod->__stream.self)
 259    {
 260        module_stream_destroy(mod);
 261
 262        if(mod->status == 3)
 263        {
 264            /* stream on_close */
 265            mod->status = -1;
 266            mod->request.status = -1;
 267
 268            lua_pushnil(lua);
 269            callback(mod);
 270        }
 271    }
 272
 273    if(mod->sync.buffer)
 274    {
 275        free(mod->sync.buffer);
 276        mod->sync.buffer = NULL;
 277    }
 278
 279    if(mod->idx_response)
 280    {
 281        luaL_unref(lua, LUA_REGISTRYINDEX, mod->idx_response);
 282        mod->idx_response = 0;
 283    }
 284
 285    if(mod->idx_content)
 286    {
 287        luaL_unref(lua, LUA_REGISTRYINDEX, mod->idx_content);
 288        mod->idx_content = 0;
 289    }
 290
 291    if(mod->idx_self)
 292    {
 293        luaL_unref(lua, LUA_REGISTRYINDEX, mod->idx_self);
 294        mod->idx_self = 0;
 295    }
 296
 297    if(mod->content)
 298    {
 299        string_buffer_free(mod->content);
 300        mod->content = NULL;
 301    }
 302}
 303
 304/*
 305 *  oooooooo8 ooooooooooo oooooooooo  ooooooooooo      o      oooo     oooo
 306 * 888        88  888  88  888    888  888    88      888      8888o   888
 307 *  888oooooo     888      888oooo88   888ooo8       8  88     88 888o8 88
 308 *         888    888      888  88o    888    oo    8oooo88    88  888  88
 309 * o88oooo888    o888o    o888o  88o8 o888ooo8888 o88o  o888o o88o  8  o88o
 310 *
 311 */
 312
 313static bool seek_pcr(  module_data_t *mod
 314                     , size_t *block_size, size_t *next_block
 315                     , uint64_t *pcr)
 316{
 317    size_t count;
 318
 319    while(1)
 320    {
 321        if(mod->sync.buffer_count < 2 * TS_PACKET_SIZE)
 322            return false;
 323
 324        count = mod->sync.buffer_read + TS_PACKET_SIZE;
 325        if(count >= mod->sync.buffer_size)
 326            count -= mod->sync.buffer_size;
 327
 328        if(   mod->sync.buffer[mod->sync.buffer_read] == 0x47
 329           && mod->sync.buffer[count] == 0x47)
 330        {
 331            break;
 332        }
 333
 334        ++mod->sync.buffer_read;
 335        if(mod->sync.buffer_read >= mod->sync.buffer_size)
 336            mod->sync.buffer_read = 0;
 337
 338        --mod->sync.buffer_count;
 339    }
 340
 341    uint8_t *ptr, ts[TS_PACKET_SIZE];
 342
 343    size_t next_skip, skip = mod->sync.buffer_read + TS_PACKET_SIZE;
 344    if(skip >= mod->sync.buffer_size)
 345        skip -= mod->sync.buffer_size;
 346
 347    for(  count = TS_PACKET_SIZE
 348        ; count < mod->sync.buffer_count
 349        ; count += TS_PACKET_SIZE)
 350    {
 351        ptr = &mod->sync.buffer[skip];
 352
 353        next_skip = skip + TS_PACKET_SIZE;
 354        if(next_skip > mod->sync.buffer_size)
 355        {
 356            const size_t packet_head = mod->sync.buffer_size - skip;
 357            memcpy(ts, ptr, packet_head);
 358            next_skip -= mod->sync.buffer_size;
 359            memcpy(&ts[packet_head], mod->sync.buffer, next_skip);
 360            ptr = ts;
 361        }
 362
 363        if(TS_IS_PCR(ptr))
 364        {
 365            *block_size = count;
 366            *next_block = skip;
 367            *pcr = TS_GET_PCR(ptr);
 368
 369            return true;
 370        }
 371
 372        skip = (next_skip == mod->sync.buffer_size) ? 0 : next_skip;
 373    }
 374
 375    return false;
 376}
 377
 378static void on_thread_close(void *arg)
 379{
 380    module_data_t *mod = (module_data_t *)arg;
 381
 382    mod->is_thread_started = false;
 383
 384    if(mod->thread)
 385    {
 386        asc_thread_destroy(mod->thread);
 387        mod->thread = NULL;
 388    }
 389
 390    if(mod->thread_output)
 391    {
 392        asc_thread_buffer_destroy(mod->thread_output);
 393        mod->thread_output = NULL;
 394    }
 395
 396    on_close(mod);
 397}
 398
 399static void on_thread_read(void *arg)
 400{
 401    module_data_t *mod = (module_data_t *)arg;
 402
 403    uint8_t ts[TS_PACKET_SIZE];
 404    const ssize_t r = asc_thread_buffer_read(mod->thread_output, ts, sizeof(ts));
 405    if(r == sizeof(ts))
 406        module_stream_send(mod, ts);
 407}
 408
 409static void thread_loop(void *arg)
 410{
 411    module_data_t *mod = (module_data_t *)arg;
 412
 413    uint8_t *ptr, ts[TS_PACKET_SIZE];
 414
 415    mod->is_thread_started = true;
 416
 417    while(mod->is_thread_started)
 418    {
 419        // block sync
 420        uint64_t   pcr
 421                 , system_time, system_time_check
 422                 , block_time, block_time_total = 0;
 423        size_t block_size = 0, next_block;
 424
 425        bool reset = true;
 426
 427        asc_log_info(MSG("buffering..."));
 428
 429        // flush
 430        mod->sync.buffer_count = 0;
 431        mod->sync.buffer_write = 0;
 432        mod->sync.buffer_read = 0;
 433
 434        // check timeout
 435        system_time_check = asc_utime();
 436
 437        while(   mod->is_thread_started
 438              && mod->sync.buffer_write < mod->sync.buffer_size)
 439        {
 440            system_time = asc_utime();
 441
 442            const ssize_t size = asc_socket_recv(  mod->sock
 443                                                 , &mod->sync.buffer[mod->sync.buffer_write]
 444                                                 , mod->sync.buffer_size - mod->sync.buffer_write);
 445            if(size > 0)
 446            {
 447                system_time_check = system_time;
 448                mod->sync.buffer_write += size;
 449            }
 450            else
 451            {
 452                if(system_time - system_time_check >= (uint32_t)mod->timeout_ms * 1000)
 453                {
 454                    asc_log_error(MSG("receiving timeout"));
 455                    return;
 456                }
 457                asc_usleep(1000);
 458            }
 459        }
 460        mod->sync.buffer_count = mod->sync.buffer_write;
 461        if(mod->sync.buffer_write == mod->sync.buffer_size)
 462            mod->sync.buffer_write = 0;
 463
 464        if(!seek_pcr(mod, &block_size, &next_block, &mod->pcr))
 465        {
 466            asc_log_error(MSG("first PCR is not found"));
 467            return;
 468        }
 469
 470        mod->sync.buffer_count -= block_size;
 471        mod->sync.buffer_read = next_block;
 472
 473        reset = true;
 474
 475        while(mod->is_thread_started)
 476        {
 477            if(reset)
 478            {
 479                reset = false;
 480                block_time_total = asc_utime();
 481            }
 482
 483            if(   mod->is_thread_started
 484               && mod->sync.buffer_count < mod->sync.buffer_size)
 485            {
 486                const size_t tail = (mod->sync.buffer_read > mod->sync.buffer_write)
 487                                  ? (mod->sync.buffer_read - mod->sync.buffer_write)
 488                                  : (mod->sync.buffer_size - mod->sync.buffer_write);
 489
 490                const ssize_t l = asc_socket_recv(  mod->sock
 491                                                  , &mod->sync.buffer[mod->sync.buffer_write]
 492                                                  , tail);
 493                if(l > 0)
 494                {
 495                    mod->sync.buffer_write += l;
 496                    if(mod->sync.buffer_write >= mod->sync.buffer_size)
 497                        mod->sync.buffer_write = 0;
 498                    mod->sync.buffer_count += l;
 499                }
 500            }
 501
 502            // get PCR
 503            if(!seek_pcr(mod, &block_size, &next_block, &pcr))
 504            {
 505                asc_log_error(MSG("next PCR is not found"));
 506                break;
 507            }
 508            block_time = mpegts_pcr_block_us(&mod->pcr, &pcr);
 509            mod->pcr = pcr;
 510            if(block_time == 0 || block_time > 500000)
 511            {
 512                asc_log_debug(  MSG("block time out of range: %"PRIu64"ms block_size:%lu")
 513                              , (uint64_t)(block_time / 1000), block_size);
 514
 515                mod->sync.buffer_count -= block_size;
 516                mod->sync.buffer_read = next_block;
 517
 518                reset = true;
 519                continue;
 520            }
 521
 522            system_time = asc_utime();
 523            if(block_time_total > system_time + 100)
 524                asc_usleep(block_time_total - system_time);
 525
 526            const uint32_t ts_count = block_size / TS_PACKET_SIZE;
 527            const uint32_t ts_sync = block_time / ts_count;
 528            const uint32_t block_time_tail = block_time % ts_count;
 529
 530            system_time_check = asc_utime();
 531
 532            while(mod->is_thread_started && mod->sync.buffer_read != next_block)
 533            {
 534                // sending
 535                ptr = &mod->sync.buffer[mod->sync.buffer_read];
 536                size_t next_packet = mod->sync.buffer_read + TS_PACKET_SIZE;
 537                if(next_packet < mod->sync.buffer_size)
 538                {
 539                    mod->sync.buffer_read = next_packet;
 540                }
 541                else if(next_packet > mod->sync.buffer_size)
 542                {
 543                    const size_t packet_head = mod->sync.buffer_size - mod->sync.buffer_read;
 544                    memcpy(ts, ptr, packet_head);
 545                    mod->sync.buffer_read = next_packet - mod->sync.buffer_size;
 546                    memcpy(&ts[packet_head], mod->sync.buffer, mod->sync.buffer_read);
 547                    ptr = ts;
 548                }
 549                else /* next_packet == mod->sync.buffer_size */
 550                {
 551                    mod->sync.buffer_read = 0;
 552                }
 553
 554                const ssize_t write_size = asc_thread_buffer_write(  mod->thread_output
 555                                                                   , ptr
 556                                                                   , TS_PACKET_SIZE);
 557                if(write_size != TS_PACKET_SIZE)
 558                {
 559                    // overflow
 560                }
 561
 562                system_time = asc_utime();
 563                block_time_total += ts_sync;
 564
 565                if(  (system_time < system_time_check) /* <-0s */
 566                   ||(system_time > system_time_check + 1000000)) /* >+1s */
 567                {
 568                    asc_log_warning(MSG("system time changed"));
 569
 570                    mod->sync.buffer_read = next_block;
 571
 572                    reset = true;
 573                    break;
 574                }
 575                system_time_check = system_time;
 576
 577                if(block_time_total > system_time + 100)
 578                    asc_usleep(block_time_total - system_time);
 579            }
 580            mod->sync.buffer_count -= block_size;
 581
 582            if(reset)
 583                continue;
 584
 585            system_time = asc_utime();
 586            if(system_time > block_time_total + 100000)
 587            {
 588                asc_log_warning(  MSG("wrong syncing time. -%"PRIu64"ms")
 589                                , (system_time - block_time_total) / 1000);
 590                reset = true;
 591            }
 592
 593            block_time_total += block_time_tail;
 594        }
 595    }
 596}
 597
 598static void check_is_active(void *arg)
 599{
 600    module_data_t *mod = (module_data_t *)arg;
 601
 602    if(mod->is_active)
 603    {
 604        mod->is_active = false;
 605        return;
 606    }
 607
 608    asc_log_error(MSG("receiving timeout"));
 609    on_close(mod);
 610}
 611
 612static void on_ts_read(void *arg)
 613{
 614    module_data_t *mod = (module_data_t *)arg;
 615
 616    ssize_t size = asc_socket_recv(  mod->sock
 617                                   , &mod->sync.buffer[mod->sync.buffer_write]
 618                                   , mod->sync.buffer_size - mod->sync.buffer_write);
 619    if(size <= 0)
 620    {
 621        on_close(mod);
 622        return;
 623    }
 624
 625    mod->is_active = true;
 626    mod->sync.buffer_write += size;
 627    mod->sync.buffer_read = 0;
 628
 629    while(1)
 630    {
 631        while(mod->sync.buffer[mod->sync.buffer_read] != 0x47)
 632        {
 633            ++mod->sync.buffer_read;
 634            if(mod->sync.buffer_read >= mod->sync.buffer_write)
 635            {
 636                mod->sync.buffer_write = 0;
 637                return;
 638            }
 639        }
 640
 641        const size_t next = mod->sync.buffer_read + TS_PACKET_SIZE;
 642        if(next > mod->sync.buffer_write)
 643        {
 644            const size_t tail = mod->sync.buffer_write - mod->sync.buffer_read;
 645            if(tail > 0)
 646                memmove(mod->sync.buffer, &mod->sync.buffer[mod->sync.buffer_read], tail);
 647            mod->sync.buffer_write = tail;
 648            return;
 649        }
 650
 651        module_stream_send(mod, &mod->sync.buffer[mod->sync.buffer_read]);
 652        mod->sync.buffer_read += TS_PACKET_SIZE;
 653    }
 654}
 655
 656/*
 657 * oooooooooo  ooooooooooo      o      ooooooooo
 658 *  888    888  888    88      888      888    88o
 659 *  888oooo88   888ooo8       8  88     888    888
 660 *  888  88o    888    oo    8oooo88    888    888
 661 * o888o  88o8 o888ooo8888 o88o  o888o o888ooo88
 662 *
 663 */
 664
 665static void on_read(void *arg)
 666{
 667    module_data_t *mod = (module_data_t *)arg;
 668
 669    if(mod->timeout)
 670    {
 671        asc_timer_destroy(mod->timeout);
 672        mod->timeout = NULL;
 673    }
 674
 675    ssize_t size = asc_socket_recv(  mod->sock
 676                                   , &mod->buffer[mod->buffer_skip]
 677                                   , HTTP_BUFFER_SIZE - mod->buffer_skip);
 678    if(size <= 0)
 679    {
 680        on_close(mod);
 681        return;
 682    }
 683
 684    if(mod->receiver.callback.ptr)
 685    {
 686        mod->receiver.callback.fn(mod->receiver.arg, &mod->buffer[mod->buffer_skip], size);
 687        return;
 688    }
 689
 690    if(mod->status == 3)
 691    {
 692        asc_log_warning(MSG("received data after response"));
 693        return;
 694    }
 695
 696    size_t eoh = 0; // end of headers
 697    size_t skip = 0;
 698    mod->buffer_skip += size;
 699
 700    if(mod->status == 0)
 701    {
 702        // check empty line
 703        while(skip < mod->buffer_skip)
 704        {
 705            if(   skip + 1 < mod->buffer_skip
 706               && mod->buffer[skip + 0] == '\n' && mod->buffer[skip + 1] == '\n')
 707            {
 708                eoh = skip + 2;
 709                mod->status = 1;
 710                break;
 711            }
 712            else if(   skip + 3 < mod->buffer_skip
 713                    && mod->buffer[skip + 0] == '\r' && mod->buffer[skip + 1] == '\n'
 714                    && mod->buffer[skip + 2] == '\r' && mod->buffer[skip + 3] == '\n')
 715            {
 716                eoh = skip + 4;
 717                mod->status = 1;
 718                break;
 719            }
 720            ++skip;
 721        }
 722
 723        if(mod->status != 1)
 724            return;
 725    }
 726
 727    if(mod->status == 1)
 728    {
 729        parse_match_t m[4];
 730
 731        skip = 0;
 732
 733/*
 734 *     oooooooooo  ooooooooooo  oooooooo8 oooooooooo
 735 *      888    888  888    88  888         888    888
 736 *      888oooo88   888ooo8     888oooooo  888oooo88
 737 * ooo  888  88o    888    oo          888 888
 738 * 888 o888o  88o8 o888ooo8888 o88oooo888 o888o
 739 *
 740 */
 741
 742        if(!http_parse_response(mod->buffer, eoh, m))
 743        {
 744            call_error(mod, "failed to parse response line");
 745            on_close(mod);
 746            return;
 747        }
 748
 749        lua_newtable(lua);
 750        const int response = lua_gettop(lua);
 751
 752        lua_pushvalue(lua, -1);
 753        if(mod->idx_response)
 754            luaL_unref(lua, LUA_REGISTRYINDEX, mod->idx_response);
 755        mod->idx_response = luaL_ref(lua, LUA_REGISTRYINDEX);
 756
 757        lua_pushlstring(lua, &mod->buffer[m[1].so], m[1].eo - m[1].so);
 758        lua_setfield(lua, response, __version);
 759
 760        mod->status_code = atoi(&mod->buffer[m[2].so]);
 761        lua_pushnumber(lua, mod->status_code);
 762        lua_setfield(lua, response, __code);
 763
 764        lua_pushlstring(lua, &mod->buffer[m[3].so], m[3].eo - m[3].so);
 765        lua_setfield(lua, response, __message);
 766
 767        skip += m[0].eo;
 768
 769/*
 770 *     ooooo ooooo ooooooooooo      o      ooooooooo  ooooooooooo oooooooooo   oooooooo8
 771 *      888   888   888    88      888      888    88o 888    88   888    888 888
 772 *      888ooo888   888ooo8       8  88     888    888 888ooo8     888oooo88   888oooooo
 773 * ooo  888   888   888    oo    8oooo88    888    888 888    oo   888  88o           888
 774 * 888 o888o o888o o888ooo8888 o88o  o888o o888ooo88  o888ooo8888 o888o  88o8 o88oooo888
 775 *
 776 */
 777
 778        lua_newtable(lua);
 779        lua_pushvalue(lua, -1);
 780        lua_setfield(lua, response, __headers);
 781        const int headers = lua_gettop(lua);
 782
 783        while(skip < eoh)
 784        {
 785            if(!http_parse_header(&mod->buffer[skip], eoh - skip, m))
 786            {
 787                call_error(mod, "failed to parse response headers");
 788                on_close(mod);
 789                return;
 790            }
 791
 792            if(m[1].eo == 0)
 793            { /* empty line */
 794                skip += m[0].eo;
 795                mod->status = 2;
 796                break;
 797            }
 798
 799            lua_string_to_lower(&mod->buffer[skip], m[1].eo);
 800            lua_pushlstring(lua, &mod->buffer[skip + m[2].so], m[2].eo - m[2].so);
 801            lua_settable(lua, headers);
 802
 803            skip += m[0].eo;
 804        }
 805
 806        mod->chunk_left = 0;
 807        mod->is_content_length = false;
 808
 809        if(mod->content)
 810        {
 811            free(mod->content);
 812            mod->content = NULL;
 813        }
 814
 815        lua_getfield(lua, headers, "content-length");
 816        if(lua_isnumber(lua, -1))
 817        {
 818            mod->chunk_left = lua_tonumber(lua, -1);
 819            if(mod->chunk_left > 0)
 820            {
 821                mod->is_content_length = true;
 822            }
 823        }
 824        lua_pop(lua, 1); // content-length
 825
 826        lua_getfield(lua, headers, "transfer-encoding");
 827        if(lua_isstring(lua, -1))
 828        {
 829            const char *encoding = lua_tostring(lua, -1);
 830            mod->is_chunked = (strcmp(encoding, "chunked") == 0);
 831        }
 832        lua_pop(lua, 1); // transfer-encoding
 833
 834        if(mod->is_content_length || mod->is_chunked)
 835            mod->content = string_buffer_alloc();
 836
 837        lua_pop(lua, 2); // headers + response
 838
 839        if(   (mod->is_head)
 840           || (mod->status_code >= 100 && mod->status_code < 200)
 841           || (mod->status_code == 204)
 842           || (mod->status_code == 304))
 843        {
 844            mod->status = 3;
 845
 846            lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_response);
 847            callback(mod);
 848
 849            if(mod->is_connection_close)
 850                on_close(mod);
 851
 852            mod->buffer_skip = 0;
 853            return;
 854        }
 855
 856        if(mod->is_stream && mod->status_code == 200)
 857        {
 858            mod->status = 3;
 859
 860            lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_response);
 861            lua_pushboolean(lua, mod->is_stream);
 862            lua_setfield(lua, -2, __stream);
 863            callback(mod);
 864
 865            mod->sync.buffer = (uint8_t *)malloc(mod->sync.buffer_size);
 866
 867            if(!mod->config.sync)
 868            {
 869                mod->timeout = asc_timer_init(mod->timeout_ms, check_is_active, mod);
 870
 871                asc_socket_set_on_read(mod->sock, on_ts_read);
 872                asc_socket_set_on_ready(mod->sock, NULL);
 873            }
 874            else
 875            {
 876                asc_socket_set_on_read(mod->sock, NULL);
 877                asc_socket_set_on_ready(mod->sock, NULL);
 878                asc_socket_set_on_close(mod->sock, NULL);
 879
 880                mod->thread = asc_thread_init(mod);
 881                mod->thread_output = asc_thread_buffer_init(mod->sync.buffer_size);
 882                asc_thread_start(  mod->thread
 883                                 , thread_loop
 884                                 , on_thread_read, mod->thread_output
 885                                 , on_thread_close);
 886            }
 887
 888            mod->buffer_skip = 0;
 889            return;
 890        }
 891
 892        if(!mod->content)
 893        {
 894            mod->status = 3;
 895
 896            lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_response);
 897            callback(mod);
 898
 899            if(mod->is_connection_close)
 900                on_close(mod);
 901
 902            mod->buffer_skip = 0;
 903            return;
 904        }
 905    }
 906
 907/*
 908 *       oooooooo8   ooooooo  oooo   oooo ooooooooooo ooooooooooo oooo   oooo ooooooooooo
 909 *     o888     88 o888   888o 8888o  88  88  888  88  888    88   8888o  88  88  888  88
 910 *     888         888     888 88 888o88      888      888ooo8     88 888o88      888
 911 * ooo 888o     oo 888o   o888 88   8888      888      888    oo   88   8888      888
 912 * 888  888oooo88    88ooo88  o88o    88     o888o    o888ooo8888 o88o    88     o888o
 913 *
 914 */
 915
 916    // Transfer-Encoding: chunked
 917    if(mod->is_chunked)
 918    {
 919        parse_match_t m[2];
 920
 921        while(skip < mod->buffer_skip)
 922        {
 923            if(!mod->chunk_left)
 924            {
 925                if(!http_parse_chunk(&mod->buffer[skip], mod->buffer_skip - skip, m))
 926                {
 927                    call_error(mod, "invalid chunk");
 928                    on_close(mod);
 929                    return;
 930                }
 931
 932                mod->chunk_left = 0;
 933                for(size_t i = m[1].so; i < m[1].eo; ++i)
 934                {
 935                    char c = mod->buffer[skip + i];
 936                    if(c >= '0' && c <= '9')
 937                        mod->chunk_left = (mod->chunk_left << 4) | (c - '0');
 938                    else if(c >= 'a' && c <= 'f')
 939                        mod->chunk_left = (mod->chunk_left << 4) | (c - 'a' + 0x0A);
 940                    else if(c >= 'A' && c <= 'F')
 941                        mod->chunk_left = (mod->chunk_left << 4) | (c - 'A' + 0x0A);
 942                }
 943                skip += m[0].eo;
 944
 945                if(!mod->chunk_left)
 946                {
 947                    lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_response);
 948                    string_buffer_push(lua, mod->content);
 949                    mod->content = NULL;
 950                    lua_setfield(lua, -2, __content);
 951                    mod->status = 3;
 952                    callback(mod);
 953
 954                    if(mod->is_connection_close)
 955                    {
 956                        on_close(mod);
 957                        return;
 958                    }
 959
 960                    break;
 961                }
 962
 963                mod->chunk_left += 2;
 964            }
 965
 966            const size_t tail = size - skip;
 967            if(mod->chunk_left <= tail)
 968            {
 969                string_buffer_addlstring(mod->content, &mod->buffer[skip], mod->chunk_left - 2);
 970
 971                skip += mod->chunk_left;
 972                mod->chunk_left = 0;
 973            }
 974            else
 975            {
 976                string_buffer_addlstring(mod->content, &mod->buffer[skip], tail);
 977                mod->chunk_left -= tail;
 978                break;
 979            }
 980        }
 981
 982        mod->buffer_skip = 0;
 983        return;
 984    }
 985
 986    // Content-Length: *
 987    if(mod->is_content_length)
 988    {
 989        const size_t tail = mod->buffer_skip - skip;
 990
 991        if(mod->chunk_left > tail)
 992        {
 993            string_buffer_addlstring(mod->content, &mod->buffer[skip], tail);
 994            mod->chunk_left -= tail;
 995        }
 996        else
 997        {
 998            string_buffer_addlstring(mod->content, &mod->buffer[skip], mod->chunk_left);
 999            mod->chunk_left = 0;
1000
1001            lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_response);
1002            string_buffer_push(lua, mod->content);
1003            mod->content = NULL;
1004            lua_setfield(lua, -2, __content);
1005            mod->status = 3;
1006            callback(mod);
1007
1008            if(mod->is_connection_close)
1009            {
1010                on_close(mod);
1011                return;
1012            }
1013        }
1014
1015        mod->buffer_skip = 0;
1016        return;
1017    }
1018}
1019
1020/*
1021 *  oooooooo8 ooooooooooo oooo   oooo ooooooooo
1022 * 888         888    88   8888o  88   888    88o
1023 *  888oooooo  888ooo8     88 888o88   888    888
1024 *         888 888    oo   88   8888   888    888
1025 * o88oooo888 o888ooo8888 o88o    88  o888ooo88
1026 *
1027 */
1028
1029static void on_ready_send_content(void *arg)
1030{
1031    module_data_t *mod = (module_data_t *)arg;
1032
1033    asc_assert(mod->request.size > 0, MSG("invalid content size"));
1034
1035    const size_t rem = mod->request.size - mod->request.skip;
1036    const size_t cap = (rem > HTTP_BUFFER_SIZE) ? HTTP_BUFFER_SIZE : rem;
1037
1038    const ssize_t send_size = asc_socket_send(  mod->sock
1039                                              , &mod->request.buffer[mod->request.skip]
1040                                              , cap);
1041    if(send_size == -1)
1042    {
1043        asc_log_error(MSG("failed to send content [%s]"), asc_socket_error());
1044        on_close(mod);
1045        return;
1046    }
1047    mod->request.skip += send_size;
1048
1049    if(mod->request.skip >= mod->request.size)
1050    {
1051        mod->request.buffer = NULL;
1052
1053        luaL_unref(lua, LUA_REGISTRYINDEX, mod->request.idx_body);
1054        mod->request.idx_body = 0;
1055
1056        mod->request.status = 3;
1057
1058        asc_socket_set_on_ready(mod->sock, NULL);
1059    }
1060}
1061
1062static void on_ready_send_request(void *arg)
1063{
1064    module_data_t *mod = (module_data_t *)arg;
1065
1066    asc_assert(mod->request.size > 0, MSG("invalid request size"));
1067
1068    const size_t rem = mod->request.size - mod->request.skip;
1069    const size_t cap = (rem > HTTP_BUFFER_SIZE) ? HTTP_BUFFER_SIZE : rem;
1070
1071    const ssize_t send_size = asc_socket_send(  mod->sock
1072                                              , &mod->request.buffer[mod->request.skip]
1073                                              , cap);
1074    if(send_size == -1)
1075    {
1076        asc_log_error(MSG("failed to send response [%s]"), asc_socket_error());
1077        on_close(mod);
1078        return;
1079    }
1080    mod->request.skip += send_size;
1081
1082    if(mod->request.skip >= mod->request.size)
1083    {
1084        free((void *)mod->request.buffer);
1085        mod->request.buffer = NULL;
1086
1087        if(mod->request.idx_body)
1088        {
1089            lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->request.idx_body);
1090            mod->request.buffer = lua_tostring(lua, -1);
1091            mod->request.size = luaL_len(lua, -1);
1092            mod->request.skip = 0;
1093            lua_pop(lua, 1);
1094
1095            mod->request.status = 2;
1096
1097            asc_socket_set_on_ready(mod->sock, on_ready_send_content);
1098        }
1099        else
1100        {
1101            mod->request.status = 3;
1102
1103            asc_socket_set_on_ready(mod->sock, NULL);
1104        }
1105    }
1106}
1107
1108static void lua_make_request(module_data_t *mod)
1109{
1110    lua_getfield(lua, -1, __method);
1111    const char *method = lua_isstring(lua, -1) ? lua_tostring(lua, -1) : __default_method;
1112    lua_pop(lua, 1);
1113
1114    mod->is_head = (strcmp(method, "HEAD") == 0);
1115
1116    lua_getfield(lua, -1, __path);
1117    mod->config.path = lua_isstring(lua, -1) ? lua_tostring(lua, -1) : __default_path;
1118    lua_pop(lua, 1);
1119
1120    lua_getfield(lua, -1, __version);
1121    const char *version = lua_isstring(lua, -1) ? lua_tostring(lua, -1) : __default_version;
1122    lua_pop(lua, 1);
1123
1124    string_buffer_t *buffer = string_buffer_alloc();
1125
1126    string_buffer_addfstring(buffer, "%s %s %s\r\n", method, mod->config.path, version);
1127
1128    lua_getfield(lua, -1, __headers);
1129    if(lua_istable(lua, -1))
1130    {
1131        for(lua_pushnil(lua); lua_next(lua, -2); lua_pop(lua, 1))
1132        {
1133            const char *h = lua_tostring(lua, -1);
1134
1135            if(!strncasecmp(h, __connection, sizeof(__connection) - 1))
1136            {
1137                const char *hp = &h[sizeof(__connection) - 1];
1138                if(!strncasecmp(hp, __close, sizeof(__close) - 1))
1139                    mod->is_connection_close = true;
1140                else if(!strncasecmp(hp, __keep_alive, sizeof(__keep_alive) - 1))
1141                    mod->is_connection_keep_alive = true;
1142            }
1143
1144            string_buffer_addfstring(buffer, "%s\r\n", h);
1145        }
1146    }
1147    lua_pop(lua, 1); // headers
1148
1149    string_buffer_addlstring(buffer, "\r\n", 2);
1150
1151    mod->request.buffer = string_buffer_release(buffer, &mod->request.size);
1152    mod->request.skip = 0;
1153
1154    if(mod->request.idx_body)
1155    {
1156        luaL_unref(lua, LUA_REGISTRYINDEX, mod->request.idx_body);
1157        mod->request.idx_body = 0;
1158    }
1159
1160    lua_getfield(lua, -1, __content);
1161    if(lua_isstring(lua, -1))
1162        mod->request.idx_body = luaL_ref(lua, LUA_REGISTRYINDEX);
1163    else
1164        lua_pop(lua, 1);
1165}
1166
1167static void on_connect(void *arg)
1168{
1169    module_data_t *mod = (module_data_t *)arg;
1170
1171    mod->request.status = 1;
1172
1173    asc_timer_destroy(mod->timeout);
1174    mod->timeout = asc_timer_init(mod->timeout_ms, timeout_callback, mod);
1175
1176    lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self);
1177    lua_getfield(lua, -1, "__options");
1178    lua_make_request(mod);
1179    lua_pop(lua, 2); // self + __options
1180
1181    asc_socket_set_on_read(mod->sock, on_read);
1182    asc_socket_set_on_ready(mod->sock, on_ready_send_request);
1183}
1184
1185static void on_upstream_ready(void *arg)
1186{
1187    module_data_t *mod = (module_data_t *)arg;
1188
1189    if(mod->sync.buffer_count > 0)
1190    {
1191        size_t block_size = (mod->sync.buffer_write > mod->sync.buffer_read)
1192                          ? (mod->sync.buffer_write - mod->sync.buffer_read)
1193                          : (mod->sync.buffer_size - mod->sync.buffer_read);
1194
1195        if(block_size > mod->sync.buffer_count)
1196            block_size = mod->sync.buffer_count;
1197
1198        const ssize_t send_size = asc_socket_send(  mod->sock
1199                                                  , &mod->sync.buffer[mod->sync.buffer_read]
1200                                                  , block_size);
1201
1202        if(send_size > 0)
1203        {
1204            mod->sync.buffer_count -= send_size;
1205            mod->sync.buffer_read += send_size;
1206            if(mod->sync.buffer_read >= mod->sync.buffer_size)
1207                mod->sync.buffer_read = 0;
1208        }
1209        else if(send_size == -1)
1210        {
1211            asc_log_error(  MSG("failed to send ts (%lu bytes) [%s]")
1212                          , block_size, asc_socket_error());
1213            on_close(mod);
1214            return;
1215        }
1216    }
1217
1218    if(mod->sync.buffer_count == 0)
1219    {
1220        asc_socket_set_on_ready(mod->sock, NULL);
1221        mod->is_socket_busy = false;
1222    }
1223}
1224
1225static void on_ts(module_data_t *mod, const uint8_t *ts)
1226{
1227    if(mod->status != 3 || mod->status_code != 200)
1228        return;
1229
1230    if(mod->sync.buffer_count + TS_PACKET_SIZE >= mod->sync.buffer_size)
1231    {
1232        // overflow
1233        mod->sync.buffer_count = 0;
1234        mod->sync.buffer_read = 0;
1235        mod->sync.buffer_write = 0;
1236        if(mod->is_socket_busy)
1237        {
1238            asc_socket_set_on_ready(mod->sock, NULL);
1239            mod->is_socket_busy = false;
1240        }
1241        return;
1242    }
1243
1244    const size_t buffer_write = mod->sync.buffer_write + TS_PACKET_SIZE;
1245    if(buffer_write < mod->sync.buffer_size)
1246    {
1247        memcpy(&mod->sync.buffer[mod->sync.buffer_write], ts, TS_PACKET_SIZE);
1248        mod->sync.buffer_write = buffer_write;
1249    }
1250    else if(buffer_write > mod->sync.buffer_size)
1251    {
1252        const size_t ts_head = mod->sync.buffer_size - mod->sync.buffer_write;
1253        memcpy(&mod->sync.buffer[mod->sync.buffer_write], ts, ts_head);
1254        mod->sync.buffer_write = TS_PACKET_SIZE - ts_head;
1255        memcpy(mod->sync.buffer, &ts[ts_head], mod->sync.buffer_write);
1256    }
1257    else
1258    {
1259        memcpy(&mod->sync.buffer[mod->sync.buffer_write], ts, TS_PACKET_SIZE);
1260        mod->sync.buffer_write = 0;
1261    }
1262    mod->sync.buffer_count += TS_PACKET_SIZE;
1263
1264    if(   mod->is_socket_busy == false
1265       && mod->sync.buffer_count >= mod->sync.buffer_fill)
1266    {
1267        asc_socket_set_on_ready(mod->sock, on_upstream_ready);
1268        mod->is_socket_busy = true;
1269    }
1270}
1271
1272/*
1273 * oooo     oooo  ooooooo  ooooooooo  ooooo  oooo ooooo       ooooooooooo
1274 *  8888o   888 o888   888o 888    88o 888    88   888         888    88
1275 *  88 888o8 88 888     888 888    888 888    88   888         888ooo8
1276 *  88  888  88 888o   o888 888    888 888    88   888      o  888    oo
1277 * o88o  8  o88o  88ooo88  o888ooo88    888oo88   o888ooooo88 o888ooo8888
1278 *
1279 */
1280
1281static int method_set_receiver(module_data_t *mod)
1282{
1283    if(lua_isnil(lua, -1))
1284    {
1285        mod->receiver.arg = NULL;
1286        mod->receiver.callback.ptr = NULL;
1287    }
1288    else
1289    {
1290        mod->receiver.arg = lua_touserdata(lua, -2);
1291        mod->receiver.callback.ptr = lua_touserdata(lua, -1);
1292    }
1293    return 0;
1294}
1295
1296static int method_send(module_data_t *mod)
1297{
1298    mod->status = 0;
1299
1300    if(mod->timeout)
1301        asc_timer_destroy(mod->timeout);
1302    mod->timeout = asc_timer_init(mod->timeout_ms, timeout_callback, mod);
1303
1304    asc_assert(lua_istable(lua, 2), MSG(":send() table required"));
1305    lua_pushvalue(lua, 2);
1306    lua_make_request(mod);
1307    lua_pop(lua, 2); // :send() options
1308
1309    asc_socket_set_on_read(mod->sock, on_read);
1310    asc_socket_set_on_ready(mod->sock, on_ready_send_request);
1311
1312    return 0;
1313}
1314
1315static int method_close(module_data_t *mod)
1316{
1317    mod->status = -1;
1318    mod->request.status = -1;
1319    on_close(mod);
1320
1321    return 0;
1322}
1323
1324static void module_init(module_data_t *mod)
1325{
1326    module_option_string("host", &mod->config.host, NULL);
1327    asc_assert(mod->config.host != NULL, MSG("option 'host' is required"));
1328
1329    mod->config.port = 80;
1330    module_option_number("port", &mod->config.port);
1331
1332    mod->config.path = __default_path;
1333    module_option_string(__path, &mod->config.path, NULL);
1334
1335    lua_getfield(lua, 2, __callback);
1336    asc_assert(lua_isfunction(lua, -1), MSG("option 'callback' is required"));
1337    lua_pop(lua, 1); // callback
1338
1339    // store self in registry
1340    lua_pushvalue(lua, 3);
1341    mod->idx_self = luaL_ref(lua, LUA_REGISTRYINDEX);
1342
1343    module_option_boolean(__stream, &mod->is_stream);
1344    if(mod->is_stream)
1345    {
1346        module_stream_init(mod, NULL);
1347
1348        int value = 0;
1349        module_option_number("sync", &value);
1350        if(value > 0)
1351            mod->config.sync = true;
1352        else
1353            value = 1;
1354
1355        mod->sync.buffer_size = value * 1024 * 1024;
1356    }
1357
1358    lua_getfield(lua, MODULE_OPTIONS_IDX, "upstream");
1359    if(lua_type(lua, -1) == LUA_TLIGHTUSERDATA)
1360    {
1361        asc_assert(mod->is_stream != true, MSG("option 'upstream' is not allowed in stream mode"));
1362
1363        module_stream_init(mod, on_ts);
1364
1365        int value = 1024;
1366        module_option_number("buffer_size", &value);
1367        mod->sync.buffer_size = value * 1024;
1368        mod->sync.buffer = (uint8_t *)malloc(mod->sync.buffer_size);
1369
1370        value = 128;
1371        module_option_number("buffer_fill", &value);
1372        mod->sync.buffer_fill = value * 1024;
1373    }
1374    lua_pop(lua, 1);
1375
1376    mod->timeout_ms = 10;
1377    module_option_number("timeout", &mod->timeout_ms);
1378    mod->timeout_ms *= 1000;
1379    mod->timeout = asc_timer_init(mod->timeout_ms, timeout_callback, mod);
1380
1381    bool sctp = false;
1382    module_option_boolean("sctp", &sctp);
1383    if(sctp == true)
1384        mod->sock = asc_socket_open_sctp4(mod);
1385    else
1386        mod->sock = asc_socket_open_tcp4(mod);
1387
1388    asc_socket_connect(mod->sock, mod->config.host, mod->config.port, on_connect, on_close);
1389}
1390
1391static void module_destroy(module_data_t *mod)
1392{
1393    mod->status = -1;
1394    mod->request.status = -1;
1395
1396    on_close(mod);
1397}
1398
1399MODULE_STREAM_METHODS()
1400MODULE_LUA_METHODS()
1401{
1402    MODULE_STREAM_METHODS_REF(),
1403    { "send", method_send },
1404    { "close", method_close },
1405    { "set_receiver", method_set_receiver },
1406};
1407
1408MODULE_LUA_REGISTER(http_request)