Subversion Repositories Kolibri OS

Rev

Rev 7101 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2017. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  HTTP library for KolibriOS                                     ;;
  7. ;;                                                                 ;;
  8. ;;   Written by hidnplayr@kolibrios.org                            ;;
  9. ;;   Proxy code written by CleverMouse                             ;;
  10. ;;                                                                 ;;
  11. ;;         GNU GENERAL PUBLIC LICENSE                              ;;
  12. ;;          Version 2, June 1991                                   ;;
  13. ;;                                                                 ;;
  14. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  15.  
  16. ; references:
  17. ; "HTTP made really easy", http://www.jmarshall.com/easy/http/
  18. ; "Hypertext Transfer Protocol -- HTTP/1.1", http://tools.ietf.org/html/rfc2616
  19.  
  20.  
  21.         URLMAXLEN       = 65535
  22.         BUFFERSIZE      = 8192
  23.         TIMEOUT         = 500  ; in 1/100 s
  24.  
  25.         __DEBUG__       = 1
  26.         __DEBUG_LEVEL__ = 1
  27.  
  28.  
  29. format MS COFF
  30.  
  31. public @EXPORT as 'EXPORTS'
  32.  
  33. include '../../../struct.inc'
  34. include '../../../proc32.inc'
  35. include '../../../macros.inc'
  36. purge section,mov,add,sub
  37. include '../../../debug-fdo.inc'
  38.  
  39. include '../../../network.inc'
  40. include 'http.inc'
  41.  
  42. virtual at 0
  43.         http_msg http_msg
  44. end virtual
  45.  
  46. macro copy_till_zero {
  47. local   .copyloop, .copydone
  48.   .copyloop:
  49.         lodsb
  50.         test    al, al
  51.         jz      .copydone
  52.         stosb
  53.         jmp     .copyloop
  54.   .copydone:
  55. }
  56.  
  57. macro HTTP_init_buffer buffer, socketnum, flags {
  58.  
  59.         mov     eax, buffer
  60.         push    socketnum
  61.         popd    [eax + http_msg.socket]
  62.         lea     esi, [eax + http_msg.http_header]
  63.         push    flags
  64.         pop     [eax + http_msg.flags]
  65.         or      [eax + http_msg.flags], FLAG_CONNECTED
  66.         mov     [eax + http_msg.write_ptr], esi
  67.         mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.http_header
  68.         mov     [eax + http_msg.chunk_ptr], 0
  69.  
  70.         mov     [eax + http_msg.status], 0
  71.         mov     [eax + http_msg.header_length], 0
  72.         mov     [eax + http_msg.content_ptr], 0
  73.         mov     [eax + http_msg.content_length], 0
  74.         mov     [eax + http_msg.content_received], 0
  75.  
  76.         push    eax ebp
  77.         mov     ebp, eax
  78.         mcall   26, 9
  79.         mov     [ebp + http_msg.timestamp], eax
  80.         pop     ebp eax
  81. }
  82.  
  83. section '.flat' code readable align 16
  84.  
  85. ;;===========================================================================;;
  86. lib_init: ;//////////////////////////////////////////////////////////////////;;
  87. ;;---------------------------------------------------------------------------;;
  88. ;? Library entry point (called after library load)                           ;;
  89. ;;---------------------------------------------------------------------------;;
  90. ;> eax = pointer to memory allocation routine                                ;;
  91. ;> ebx = pointer to memory freeing routine                                   ;;
  92. ;> ecx = pointer to memory reallocation routine                              ;;
  93. ;> edx = pointer to library loading routine                                  ;;
  94. ;;---------------------------------------------------------------------------;;
  95. ;< eax = 1 (fail) / 0 (ok)                                                   ;;
  96. ;;===========================================================================;;
  97.         mov     [mem.alloc], eax
  98.         mov     [mem.free], ebx
  99.         mov     [mem.realloc], ecx
  100.         mov     [dll.load], edx
  101.  
  102.         invoke  dll.load, @IMPORT
  103.         test    eax, eax
  104.         jnz     .error
  105.  
  106. ; load proxy settings
  107.         pusha
  108.         invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
  109.         invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
  110.         mov     [proxyPort], eax
  111.         invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
  112.         invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
  113.         popa
  114.  
  115.         DEBUGF  1, "HTTP library: init OK\n"
  116.         xor     eax, eax
  117.         ret
  118.  
  119.   .error:
  120.         DEBUGF  2, "ERROR loading http.obj dependencies\n"
  121.         xor     eax, eax
  122.         inc     eax
  123.         ret
  124.  
  125.  
  126. ;;================================================================================================;;
  127. proc HTTP_disconnect identifier ;/////////////////////////////////////////////////////////////////;;
  128. ;;------------------------------------------------------------------------------------------------;;
  129. ;? Stops the open connection                                                                      ;;
  130. ;;------------------------------------------------------------------------------------------------;;
  131. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  132. ;;------------------------------------------------------------------------------------------------;;
  133. ;< none                                                                                           ;;
  134. ;;================================================================================================;;
  135.  
  136.         pusha
  137.         mov     ebp, [identifier]
  138.  
  139.         test    [ebp + http_msg.flags], FLAG_CONNECTED
  140.         jz      .error
  141.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  142.         mcall   close, [ebp + http_msg.socket]
  143.  
  144.         popa
  145.         ret
  146.  
  147.   .error:
  148.         DEBUGF  1, "Cannot close already closed connection!\n"
  149.         popa
  150.         ret
  151.  
  152. endp
  153.  
  154.  
  155. ;;================================================================================================;;
  156. proc HTTP_free identifier ;///////////////////////////////////////////////////////////////////////;;
  157. ;;------------------------------------------------------------------------------------------------;;
  158. ;? Free the http_msg structure                                                                    ;;
  159. ;;------------------------------------------------------------------------------------------------;;
  160. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  161. ;;------------------------------------------------------------------------------------------------;;
  162. ;< none                                                                                           ;;
  163. ;;================================================================================================;;
  164.         DEBUGF  1, "HTTP_free: 0x%x\n", [identifier]
  165.         pusha
  166.         mov     ebp, [identifier]
  167.  
  168.         test    [ebp + http_msg.flags], FLAG_CONNECTED
  169.         jz      .not_connected
  170.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  171.         mcall   close, [ebp + http_msg.socket]
  172.  
  173.   .not_connected:
  174.         invoke  mem.free, ebp
  175.  
  176.         popa
  177.         ret
  178.  
  179. endp
  180.  
  181.  
  182.  
  183. ;;================================================================================================;;
  184. proc HTTP_get URL, identifier, flags, add_header ;////////////////////////////////////////////////;;
  185. ;;------------------------------------------------------------------------------------------------;;
  186. ;? Initiates a HTTP connection, using 'GET' method.                                               ;;
  187. ;;------------------------------------------------------------------------------------------------;;
  188. ;> URL                  = pointer to ASCIIZ URL                                                   ;;
  189. ;> identifier           = Identifier of an already open connection, or NULL to create a new one.  ;;
  190. ;> flags                = Flags indicating how to threat the connection.                          ;;
  191. ;> add_header           = pointer to additional header parameters (ASCIIZ), or NULL for none.     ;;
  192. ;;------------------------------------------------------------------------------------------------;;
  193. ;< eax = 0 (error) / buffer ptr                                                                   ;;
  194. ;;================================================================================================;;
  195. locals
  196.         hostname        dd ?
  197.         pageaddr        dd ?
  198.         socketnum       dd ?
  199.         buffer          dd ?
  200.         port            dd ?
  201. endl
  202.  
  203.         and     [flags], 0xff00       ; filter out invalid flags
  204.  
  205.         pusha
  206.  
  207. ; split the URL into hostname and pageaddr
  208.         stdcall parse_url, [URL]
  209.         test    eax, eax
  210.         jz      .error
  211.         mov     [hostname], eax
  212.         mov     [pageaddr], ebx
  213.         mov     [port], ecx
  214.  
  215.         mov     eax, [identifier]
  216.         test    eax, eax
  217.         jz      .open_new
  218.         test    [eax + http_msg.flags], FLAG_CONNECTED
  219.         jz      .error
  220.         mov     eax, [eax + http_msg.socket]
  221.         mov     [socketnum], eax
  222.         jmp     .send_request
  223.  
  224. ; Connect to the other side.
  225.   .open_new:
  226.         stdcall open_connection, [hostname], [port]
  227.         test    eax, eax
  228.         jz      .error
  229.         mov     [socketnum], eax
  230.  
  231. ; Create the HTTP request.
  232.   .send_request:
  233.         invoke  mem.alloc, BUFFERSIZE
  234.         test    eax, eax
  235.         jz      .error
  236.         mov     [buffer], eax
  237.         mov     edi, eax
  238.         DEBUGF  1, "Buffer allocated: 0x%x\n", eax
  239.  
  240.         mov     esi, str_get
  241.         copy_till_zero
  242.  
  243. ; If we are using a proxy, send complete URL, otherwise send only page address.
  244.         cmp     [proxyAddr], 0
  245.         je      .no_proxy
  246.         mov     esi, str_http           ; prepend 'http://'
  247.         copy_till_zero
  248.         mov     esi, [hostname]
  249.         copy_till_zero
  250.   .no_proxy:
  251.         mov     esi, [pageaddr]
  252.         copy_till_zero
  253.  
  254.         mov     esi, str_http11
  255.         mov     ecx, str_http11.length
  256.         rep     movsb
  257.  
  258.         mov     esi, [hostname]
  259.         copy_till_zero
  260.  
  261.         cmp     byte[proxyUser], 0
  262.         je      @f
  263.         call    append_proxy_auth_header
  264.   @@:
  265.  
  266.         mov     ax, 0x0a0d
  267.         stosw
  268.  
  269.         mov     esi, [add_header]
  270.         test    esi, esi
  271.         jz      @f
  272.         copy_till_zero
  273.   @@:
  274.  
  275.         mov     esi, str_close
  276.         mov     ecx, str_close.length
  277.         test    [flags], FLAG_KEEPALIVE
  278.         jz      @f
  279.         mov     esi, str_keep
  280.         mov     ecx, str_keep.length
  281.   @@:
  282.         rep     movsb
  283.  
  284.         mov     byte[edi], 0
  285.         DEBUGF  1, "Request:\n%s", [buffer]
  286.  
  287. ; Free unused memory
  288.         push    edi
  289.         invoke  mem.free, [pageaddr]
  290.         invoke  mem.free, [hostname]
  291.         pop     esi
  292.  
  293. ; Send the request
  294.         sub     esi, [buffer]   ; length
  295.         xor     edi, edi        ; flags
  296.         mcall   send, [socketnum], [buffer]
  297.         test    eax, eax
  298.         jz      .error
  299.         DEBUGF  1, "Request has been sent to server.\n"
  300.  
  301.         cmp     [identifier], 0
  302.         je      .new_connection
  303.         invoke  mem.free, [buffer]
  304.         mov     eax, [identifier]
  305.         mov     [buffer], eax
  306.   .new_connection:
  307.         HTTP_init_buffer [buffer], [socketnum], [flags]
  308.         popa
  309.         mov     eax, [buffer]   ; return buffer ptr
  310.         ret
  311.  
  312.   .error:
  313.         DEBUGF  2, "HTTP GET error!\n"
  314.         popa
  315.         xor     eax, eax        ; return 0 = error
  316.         ret
  317.  
  318. endp
  319.  
  320.  
  321.  
  322. ;;================================================================================================;;
  323. proc HTTP_head URL, identifier, flags, add_header ;///////////////////////////////////////////////;;
  324. ;;------------------------------------------------------------------------------------------------;;
  325. ;? Initiates a HTTP connection, using 'HEAD' method.                                              ;;
  326. ;? This will only return HTTP header and status, no content                                       ;;
  327. ;;------------------------------------------------------------------------------------------------;;
  328. ;> URL                  = pointer to ASCIIZ URL                                                   ;;
  329. ;> identifier           = Identifier of an already open connection, or NULL to create a new one.  ;;
  330. ;> flags                = Flags indicating how to threat the connection.                          ;;
  331. ;> add_header           = pointer to additional header parameters (ASCIIZ), or NULL for none.     ;;
  332. ;;------------------------------------------------------------------------------------------------;;
  333. ;< eax = 0 (error) / buffer ptr                                                                   ;;
  334. ;;================================================================================================;;
  335. locals
  336.         hostname        dd ?
  337.         pageaddr        dd ?
  338.         socketnum       dd ?
  339.         buffer          dd ?
  340.         port            dd ?
  341. endl
  342.  
  343.         and     [flags], 0xff00         ; filter out invalid flags
  344.  
  345.         pusha
  346. ; split the URL into hostname and pageaddr
  347.         stdcall parse_url, [URL]
  348.         test    eax, eax
  349.         jz      .error
  350.         mov     [hostname], eax
  351.         mov     [pageaddr], ebx
  352.         mov     [port], ecx
  353.  
  354.         mov     eax, [identifier]
  355.         test    eax, eax
  356.         jz      .open_new
  357.         test    [eax + http_msg.flags], FLAG_CONNECTED
  358.         jz      .error
  359.         mov     eax, [eax + http_msg.socket]
  360.         mov     [socketnum], eax
  361.         jmp     .send_request
  362.  
  363. ; Connect to the other side.
  364.   .open_new:
  365.         stdcall open_connection, [hostname], [port]
  366.         test    eax, eax
  367.         jz      .error
  368.         mov     [socketnum], eax
  369.  
  370. ; Create the HTTP request.
  371.   .send_request:
  372.         invoke  mem.alloc, BUFFERSIZE
  373.         test    eax, eax
  374.         jz      .error
  375.         mov     [buffer], eax
  376.         mov     edi, eax
  377.         DEBUGF  1, "Buffer has been allocated.\n"
  378.  
  379.         mov     esi, str_head
  380.         copy_till_zero
  381.  
  382. ; If we are using a proxy, send complete URL, otherwise send only page address.
  383.         cmp     [proxyAddr], 0
  384.         je      .no_proxy
  385.         mov     esi, str_http           ; prepend 'http://'
  386.         copy_till_zero
  387.         mov     esi, [hostname]
  388.         copy_till_zero
  389.   .no_proxy:
  390.         mov     esi, [pageaddr]
  391.         copy_till_zero
  392.  
  393.         mov     esi, str_http11
  394.         mov     ecx, str_http11.length
  395.         rep     movsb
  396.  
  397.         mov     esi, [hostname]
  398.         copy_till_zero
  399.  
  400.         cmp     byte[proxyUser], 0
  401.         je      @f
  402.         call    append_proxy_auth_header
  403.   @@:
  404.  
  405.         mov     ax, 0x0a0d
  406.         stosw
  407.  
  408.         mov     esi, [add_header]
  409.         test    esi, esi
  410.         jz      @f
  411.         copy_till_zero
  412.   @@:
  413.  
  414.         mov     esi, str_close
  415.         mov     ecx, str_close.length
  416.         test    [flags], FLAG_KEEPALIVE
  417.         jz      @f
  418.         mov     esi, str_keep
  419.         mov     ecx, str_keep.length
  420.   @@:
  421.         rep     movsb
  422.  
  423.         mov     byte[edi], 0
  424.         DEBUGF  1, "Request:\n%s", [buffer]
  425.  
  426. ; Free unused memory
  427.         push    edi
  428.         invoke  mem.free, [pageaddr]
  429.         invoke  mem.free, [hostname]
  430.         pop     esi
  431.  
  432. ; Send the request
  433.         sub     esi, [buffer]   ; length
  434.         xor     edi, edi        ; flags
  435.         mcall   send, [socketnum], [buffer]
  436.         test    eax, eax
  437.         jz      .error
  438.         DEBUGF  1, "Request has been sent to server.\n"
  439.  
  440.         cmp     [identifier], 0
  441.         je      .new_connection
  442.         invoke  mem.free, [buffer]
  443.         mov     eax, [identifier]
  444.         mov     [buffer], eax
  445.   .new_connection:
  446.         HTTP_init_buffer [buffer], [socketnum], [flags]
  447.         popa
  448.         mov     eax, [buffer]   ; return buffer ptr
  449.         ret
  450.  
  451.   .error:
  452.         DEBUGF  2, "HTTP HEAD error!\n"
  453.         popa
  454.         xor     eax, eax        ; return 0 = error
  455.         ret
  456.  
  457. endp
  458.  
  459.  
  460. ;;================================================================================================;;
  461. proc HTTP_post URL, identifier, flags, add_header, content_type, content_length ;/////////////////;;
  462. ;;------------------------------------------------------------------------------------------------;;
  463. ;? Initiates a HTTP connection, using 'POST' method.                                              ;;
  464. ;? This method is used to send data to the HTTP server                                            ;;
  465. ;;------------------------------------------------------------------------------------------------;;
  466. ;> URL                  = pointer to ASCIIZ URL                                                   ;;
  467. ;> identifier           = Identifier of an already open connection, or NULL to create a new one.  ;;
  468. ;> flags                = Flags indicating how to threat the connection.                          ;;
  469. ;> add_header           = pointer to additional header parameters (ASCIIZ), or NULL for none.     ;;
  470. ;> content_type         = pointer to ASCIIZ string containing content type                        ;;
  471. ;> content_length       = length of content (in bytes)                                            ;;
  472. ;;------------------------------------------------------------------------------------------------;;
  473. ;< eax = 0 (error) / buffer ptr (aka Identifier)                                                  ;;
  474. ;;================================================================================================;;
  475. locals
  476.         hostname        dd ?
  477.         pageaddr        dd ?
  478.         socketnum       dd ?
  479.         buffer          dd ?
  480.         port            dd ?
  481. endl
  482.  
  483.         DEBUGF  1, "HTTP POST (%s).\n", [URL]
  484.  
  485.         and     [flags], 0xff00       ; filter out invalid flags
  486.  
  487.         pusha
  488. ; split the URL into hostname and pageaddr
  489.         stdcall parse_url, [URL]
  490.         test    eax, eax
  491.         jz      .error
  492.         mov     [hostname], eax
  493.         mov     [pageaddr], ebx
  494.         mov     [port], ecx
  495.  
  496.         mov     eax, [identifier]
  497.         test    eax, eax
  498.         jz      .open_new
  499.         test    [eax + http_msg.flags], FLAG_CONNECTED
  500.         jz      .error
  501.         mov     eax, [eax + http_msg.socket]
  502.         mov     [socketnum], eax
  503.         jmp     .send_request
  504.  
  505. ; Connect to the other side.
  506.   .open_new:
  507.         DEBUGF  1, "Opening new connection.\n"
  508.         stdcall open_connection, [hostname], [port]
  509.         test    eax, eax
  510.         jz      .error
  511.         mov     [socketnum], eax
  512.  
  513. ; Create the HTTP request.
  514.   .send_request:
  515.         invoke  mem.alloc, BUFFERSIZE
  516.         test    eax, eax
  517.         jz      .error
  518.         mov     [buffer], eax
  519.         mov     edi, eax
  520.         DEBUGF  1, "Buffer has been allocated.\n"
  521.  
  522.         mov     esi, str_post
  523.         copy_till_zero
  524.  
  525. ; If we are using a proxy, send complete URL, otherwise send only page address.
  526.         cmp     [proxyAddr], 0
  527.         je      .no_proxy
  528.         mov     esi, str_http           ; prepend 'http://'
  529.         copy_till_zero
  530.         mov     esi, [hostname]
  531.         copy_till_zero
  532.   .no_proxy:
  533.         mov     esi, [pageaddr]
  534.         copy_till_zero
  535.  
  536.         mov     esi, str_http11
  537.         mov     ecx, str_http11.length
  538.         rep     movsb
  539.  
  540.         mov     esi, [hostname]
  541.         copy_till_zero
  542.  
  543.         mov     esi, str_post_cl
  544.         mov     ecx, str_post_cl.length
  545.         rep     movsb
  546.  
  547.         mov     eax, [content_length]
  548.         call    eax_ascii_dec
  549.  
  550.         mov     esi, str_post_ct
  551.         mov     ecx, str_post_ct.length
  552.         rep     movsb
  553.  
  554.         mov     esi, [content_type]
  555.         copy_till_zero
  556.  
  557.         cmp     byte[proxyUser], 0
  558.         je      @f
  559.         call    append_proxy_auth_header
  560.   @@:
  561.  
  562.         mov     ax, 0x0a0d
  563.         stosw
  564.  
  565.         mov     esi, [add_header]
  566.         test    esi, esi
  567.         jz      @f
  568.         copy_till_zero
  569.   @@:
  570.  
  571.         mov     esi, str_close
  572.         mov     ecx, str_close.length
  573.         test    [flags], FLAG_KEEPALIVE
  574.         jz      @f
  575.         mov     esi, str_keep
  576.         mov     ecx, str_keep.length
  577.   @@:
  578.         rep     movsb
  579.  
  580.         mov     byte[edi], 0
  581.         DEBUGF  1, "Request:\n%s", [buffer]
  582.  
  583. ; Free unused memory
  584.         push    edi
  585.         invoke  mem.free, [pageaddr]
  586.         invoke  mem.free, [hostname]
  587.         pop     esi
  588.  
  589. ; Send the request
  590.         sub     esi, [buffer]   ; length
  591.         xor     edi, edi        ; flags
  592.         mcall   send, [socketnum], [buffer]
  593.         test    eax, eax
  594.         jz      .error
  595.         DEBUGF  1, "Request has been sent to server.\n"
  596.  
  597.         cmp     [identifier], 0
  598.         je      .new_connection
  599.         invoke  mem.free, [buffer]
  600.         mov     eax, [identifier]
  601.         mov     [buffer], eax
  602.   .new_connection:
  603.         HTTP_init_buffer [buffer], [socketnum], [flags]
  604.         popa
  605.         mov     eax, [buffer]   ; return buffer ptr
  606.         DEBUGF  1, "HTTP POST complete.\n"
  607.         ret
  608.  
  609.   .error:
  610.         DEBUGF  2, "HTTP POST error!\n"
  611.         popa
  612.         xor     eax, eax        ; return 0 = error
  613.         ret
  614.  
  615. endp
  616.  
  617.  
  618.  
  619. ;;================================================================================================;;
  620. proc HTTP_receive identifier ;////////////////////////////////////////////////////////////////////;;
  621. ;;------------------------------------------------------------------------------------------------;;
  622. ;? Receive data from the server, parse headers and put data in receive buffer(s).                 ;;
  623. ;? To complete a transfer, this procedure must be called over and over again untill it returns 0. ;;
  624. ;;------------------------------------------------------------------------------------------------;;
  625. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  626. ;;------------------------------------------------------------------------------------------------;;
  627. ;< eax = -1 (not finished) / 0 finished                                                           ;;
  628. ;;================================================================================================;;
  629.  
  630.         pusha
  631.         mov     ebp, [identifier]
  632.  
  633. ; If the connection is closed, return immediately
  634.         test    [ebp + http_msg.flags], FLAG_CONNECTED
  635.         jz      .connection_closed
  636.  
  637. ; If the buffer is full, allocate a new one
  638.         cmp     [ebp + http_msg.buffer_length], 0
  639.         jne     .receive
  640.  
  641.         test    [ebp + http_msg.flags], FLAG_STREAM
  642.         jz      .err_header
  643.  
  644.         test    [ebp + http_msg.flags], FLAG_REUSE_BUFFER
  645.         jz      .new_buffer
  646.  
  647.         mov     eax, [ebp + http_msg.content_ptr]
  648.         mov     [ebp + http_msg.write_ptr], eax
  649.         mov     [ebp + http_msg.buffer_length], BUFFERSIZE
  650.         jmp     .receive
  651.  
  652.   .new_buffer:
  653.         invoke  mem.alloc, BUFFERSIZE
  654.         test    eax, eax
  655.         jz      .err_no_ram
  656.         mov     [ebp + http_msg.content_ptr], eax
  657.         mov     [ebp + http_msg.write_ptr], eax
  658.         mov     [ebp + http_msg.buffer_length], BUFFERSIZE
  659.         DEBUGF  1, "New buffer: 0x%x\n", eax
  660.  
  661. ; Receive some data
  662.   .receive:
  663.         mov     edi, MSG_DONTWAIT
  664.         test    [ebp + http_msg.flags], FLAG_BLOCK
  665.         jz      @f
  666.         xor     edi, edi
  667.   @@:
  668.         mcall   recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
  669.                       [ebp + http_msg.buffer_length]
  670.         cmp     eax, 0xffffffff
  671.         je      .check_socket
  672.  
  673.         test    eax, eax
  674.         jz      .server_closed
  675.         DEBUGF  1, "Received %u bytes\n", eax
  676.  
  677. ; Update timestamp
  678.         push    eax
  679.         mcall   26, 9
  680.         mov     [ebp + http_msg.timestamp], eax
  681.         pop     eax
  682.  
  683. ; Update pointers
  684.         mov     edi, [ebp + http_msg.write_ptr]
  685.         add     [ebp + http_msg.write_ptr], eax
  686.         sub     [ebp + http_msg.buffer_length], eax
  687.  
  688. ; If data is chunked, combine chunks into contiguous data.
  689.         test    [ebp + http_msg.flags], FLAG_CHUNKED
  690.         jnz     .chunk_loop
  691.  
  692. ; Did we detect the (final) header yet?
  693.         test    [ebp + http_msg.flags], FLAG_GOT_HEADER
  694.         jnz     .header_parsed
  695.  
  696. ;--------------------------------------------------------------
  697. ;
  698. ; Header parsing code begins here
  699. ;
  700.  
  701. ; We havent found the (final) header yet, search for it..
  702.   .scan_again:
  703.         ; eax = total number of bytes received so far
  704.         mov     eax, [ebp + http_msg.write_ptr]
  705.         sub     eax, http_msg.http_header
  706.         sub     eax, ebp
  707.         sub     eax, [ebp + http_msg.header_length]
  708.         ; edi is ptr to begin of header
  709.         lea     edi, [ebp + http_msg.http_header]
  710.         add     edi, [ebp + http_msg.header_length]
  711.         ; put it in esi for next proc too
  712.         mov     esi, edi
  713.         sub     eax, 3
  714.         jle     .need_more_data_for_header
  715.   .scan_loop:
  716.         ; scan for end of header (empty line)
  717.         cmp     dword[edi], 0x0a0d0a0d                  ; end of header
  718.         je      .end_of_header
  719.         cmp     word[edi+2], 0x0a0a                     ; notice the use of offset + 2, to calculate header length correctly :)
  720.         je      .end_of_header
  721.         inc     edi
  722.         dec     eax
  723.         jnz     .scan_loop
  724.         jmp     .need_more_data_for_header
  725.  
  726.   .end_of_header:
  727.         add     edi, 4 - http_msg.http_header
  728.         sub     edi, ebp
  729.         mov     [ebp + http_msg.header_length], edi     ; If this isnt the final header, we'll use this as an offset to find real header.
  730.         DEBUGF  1, "Header length: %u\n", edi
  731.  
  732. ; Ok, we have found the header
  733.         cmp     dword[esi], 'HTTP'
  734.         jne     .err_header
  735.         cmp     dword[esi+4], '/1.0'
  736.         je      .http_1.0
  737.         cmp     dword[esi+4], '/1.1'
  738.         jne     .err_header
  739.         or      [ebp + http_msg.flags], FLAG_HTTP11
  740.   .http_1.0:
  741.         cmp     byte[esi+8], ' '
  742.         jne     .err_header
  743.  
  744.         add     esi, 9
  745.         xor     eax, eax
  746.         xor     ebx, ebx
  747.         mov     ecx, 3
  748.   .statusloop:
  749.         lodsb
  750.         sub     al, '0'
  751.         jb      .err_header
  752.         cmp     al, 9
  753.         ja      .err_header
  754.         lea     ebx, [ebx + 4*ebx]
  755.         shl     ebx, 1
  756.         add     ebx, eax
  757.         dec     ecx
  758.         jnz     .statusloop
  759.  
  760. ; Ignore "100 - Continue" lines
  761.         cmp     ebx, 100
  762.         je      .scan_again
  763.  
  764.         DEBUGF  1, "Status: %u\n", ebx
  765.         mov     [ebp + http_msg.status], ebx
  766.         or      [ebp + http_msg.flags], FLAG_GOT_HEADER
  767.  
  768. ; Now, convert all header names to lowercase.
  769. ; This way, it will be much easier to find certain header fields, later on.
  770.         lea     esi, [ebp + http_msg.http_header]
  771.         mov     ecx, [ebp + http_msg.header_length]
  772.   .need_newline:
  773.         inc     esi
  774.         dec     ecx
  775.         jz      .convert_done
  776.         cmp     byte[esi], 10
  777.         jne     .need_newline
  778. ; We have found a newline
  779. ; A line beginning with space or tabs has no header fields.
  780.         inc     esi
  781.         dec     ecx
  782.         jz      .convert_done
  783.         cmp     byte[esi], ' '
  784.         je      .need_newline
  785.         cmp     byte[esi], 9    ; horizontal tab
  786.         je      .need_newline
  787.         jmp     .convert_loop
  788.   .next_char:
  789.         inc     esi
  790.         dec     ecx
  791.         jz      .convert_done
  792.   .convert_loop:
  793.         cmp     byte[esi], ':'
  794.         je      .need_newline
  795.         cmp     byte[esi], 'A'
  796.         jb      .next_char
  797.         cmp     byte[esi], 'Z'
  798.         ja      .next_char
  799.         or      byte[esi], 0x20 ; convert to lowercase
  800.         jmp     .next_char
  801.   .convert_done:
  802.         mov     byte[esi-1], 0
  803.         lea     esi, [ebp + http_msg.http_header]
  804.         DEBUGF  1, "Header names converted to lowercase:\n%s\n", esi
  805.  
  806. ; Check for content-length header field.
  807.         stdcall HTTP_find_header_field, ebp, str_cl
  808.         test    eax, eax
  809.         jz      .no_content
  810.         or      [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  811.  
  812.         xor     edx, edx
  813.   .cl_loop:
  814.         movzx   ebx, byte[eax]
  815.         inc     eax
  816.         cmp     bl, 10
  817.         je      .cl_ok
  818.         cmp     bl, 13
  819.         je      .cl_ok
  820.         cmp     bl, ' '
  821.         je      .cl_ok
  822.         sub     bl, '0'
  823.         jb      .err_header
  824.         cmp     bl, 9
  825.         ja      .err_header
  826.         lea     edx, [edx + edx*4]      ; edx = edx*10
  827.         shl     edx, 1                  ;
  828.         add     edx, ebx
  829.         jmp     .cl_loop
  830.  
  831.   .cl_ok:
  832.         mov     [ebp + http_msg.content_length], edx
  833.         DEBUGF  1, "Content-length: %u\n", edx
  834.  
  835.         test    edx, edx
  836.         jz      .got_all_data
  837.  
  838.         call    alloc_contentbuff
  839.         test    eax, eax
  840.         jz      .err_no_ram
  841.         xor     eax, eax
  842.         jmp     .header_parsed
  843.  
  844.   .no_content:
  845.         DEBUGF  1, "Content-length not found.\n"
  846. ; We didnt find 'content-length', maybe server is using chunked transfer encoding?
  847.   .multibuffer:
  848. ; Try to find 'transfer-encoding' header.
  849.         stdcall HTTP_find_header_field, ebp, str_te
  850.         test    eax, eax
  851.         jnz     .ct_hdr_found
  852.  
  853.   .not_chunked:
  854.         mov     edx, BUFFERSIZE
  855.         call    alloc_contentbuff
  856.         test    eax, eax
  857.         jz      .err_no_ram
  858.         xor     eax, eax
  859.         jmp     .header_parsed
  860.  
  861.   .ct_hdr_found:
  862.         mov     ebx, dword[eax]
  863.         or      ebx, 0x20202020
  864.         cmp     ebx, 'chun'
  865.         jne     .not_chunked
  866.         mov     ebx, dword[eax+4]
  867.         or      ebx, 0x00202020
  868.         and     ebx, 0x00ffffff
  869.         cmp     ebx, 'ked'
  870.         jne     .not_chunked
  871.  
  872.         or      [ebp + http_msg.flags], FLAG_CHUNKED
  873.         DEBUGF  1, "Transfer type is: chunked\n"
  874.  
  875.         mov     edx, BUFFERSIZE
  876.         call    alloc_contentbuff
  877.         test    eax, eax
  878.         jz      .err_no_ram
  879.  
  880. ; Set chunk pointer where first chunk should begin.
  881.         mov     eax, [ebp + http_msg.content_ptr]
  882.         mov     [ebp + http_msg.chunk_ptr], eax
  883.  
  884. ;--------------------------------------------------------------
  885. ;
  886. ; Chunk parsing code begins here
  887. ;
  888.  
  889.   .chunk_loop:
  890.         DEBUGF  1, "chunk_loop write_ptr=0x%x chunk_ptr=0x%x\n", [ebp + http_msg.write_ptr], [ebp + http_msg.chunk_ptr]
  891.         mov     ecx, [ebp + http_msg.write_ptr]
  892.         sub     ecx, [ebp + http_msg.chunk_ptr]
  893.         jbe     .need_more_data_chunked                 ; amount of available bytes after chunkline start
  894.  
  895. ; Chunkline starts here, convert the ASCII hex number into ebx
  896.         mov     esi, [ebp + http_msg.chunk_ptr]
  897.  
  898.         xor     ebx, ebx
  899.         cmp     byte[esi], 0x0d
  900.         jne     .chunk_hex_loop
  901.         dec     ecx
  902.         jz      .need_more_data_chunked
  903.         inc     esi
  904.         cmp     byte[esi], 0x0a
  905.         jne     .chunk_hex_loop
  906.         dec     ecx
  907.         jz      .need_more_data_chunked
  908.         inc     esi
  909.   .chunk_hex_loop:
  910.         lodsb
  911.         sub     al, '0'
  912.         jb      .chunk_hex_end
  913.         cmp     al, 9
  914.         jbe     .chunk_hex
  915.         sub     al, 'A' - '0' - 10
  916.         jb      .chunk_hex_end
  917.         cmp     al, 15
  918.         jbe     .chunk_hex
  919.         sub     al, 'a' - 'A'
  920.         cmp     al, 15
  921.         ja      .chunk_hex_end
  922.   .chunk_hex:
  923.         shl     ebx, 4
  924.         add     bl, al
  925.         dec     ecx
  926.         jnz     .chunk_hex_loop
  927.         jmp     .need_more_data_chunked
  928.   .chunk_hex_end:
  929. ; Chunkline ends with a CR LF or simply LF
  930.         dec     esi
  931.   .end_of_chunkline?:
  932.         lodsb
  933.         cmp     al, 10                                  ; chunkline must always end with LF
  934.         je      .end_of_chunkline
  935.         dec     ecx
  936.         jnz     .end_of_chunkline?
  937.         xor     eax, eax
  938.         jmp     .need_more_data_chunked                 ; chunkline is incomplete, request more data
  939.   .end_of_chunkline:
  940.         DEBUGF  1, "Chunk of 0x%x bytes\n", ebx
  941. ; If chunk size is 0, all chunks have been received.
  942.         test    ebx, ebx
  943.         jz      .got_all_data_chunked
  944. ; Calculate chunkline length
  945.         mov     edx, esi
  946.         sub     edx, [ebp + http_msg.chunk_ptr]         ; edx is now length of chunkline
  947.         DEBUGF  1, "Chunkline is %u bytes long\n", edx
  948. ; Calculate how many data bytes we have received already
  949.         mov     ecx, [ebp + http_msg.write_ptr]
  950.         sub     ecx, [ebp + http_msg.chunk_ptr]
  951.         sub     ecx, edx                                ; ecx is now number of received data bytes (without chunkline)
  952. ; Update content_received counter
  953.         add     [ebp + http_msg.content_received], ecx
  954. ; Calculate new write ptr
  955.         sub     [ebp + http_msg.write_ptr], edx
  956.         test    [ebp + http_msg.flags], FLAG_STREAM
  957.         jnz     .dont_resize
  958. ; Realloc buffer, make it 'chunksize' bigger.
  959.         lea     edx, [ebx + BUFFERSIZE]
  960.         mov     [ebp + http_msg.buffer_length], edx     ; remaining space in new buffer
  961.         add     edx, [ebp + http_msg.write_ptr]
  962.         sub     edx, [ebp + http_msg.content_ptr]
  963.         DEBUGF  1, "Resizing buffer 0x%x, it will now be %u bytes\n", [ebp + http_msg.content_ptr], edx
  964.         invoke  mem.realloc, [ebp + http_msg.content_ptr], edx
  965.         DEBUGF  1, "New buffer = 0x%x\n", eax
  966.         or      eax, eax
  967.         jz      .err_no_ram
  968.         call    recalculate_pointers                    ; Because it's possible that buffer begins on another address now
  969.         add     esi, eax                                ; recalculate esi too!
  970.   .dont_resize:
  971. ; Remove chunk header (aka chunkline) from the buffer by shifting all received data after chunkt_ptr to the left
  972.         mov     edi, [ebp + http_msg.chunk_ptr]
  973.         DEBUGF  1, "Removing chunkline esi=0x%x edi=0x%x ecx=%u\n", esi, edi, ecx
  974.         rep movsb
  975. ; Update chunk ptr to point to next chunk
  976.         add     [ebp + http_msg.chunk_ptr], ebx
  977. ; Set number of received bytes to 0, we already updated content_received
  978.         xor     eax, eax
  979.         jmp     .chunk_loop
  980.  
  981. ;--------------------------------------------------------------
  982. ;
  983. ; end of proc code begins here
  984. ;
  985.  
  986.   .header_parsed:
  987.         ; Header was already parsed and connection isnt chunked.
  988.         ; Update content_received
  989.         add     [ebp + http_msg.content_received], eax
  990.         ; If we received content-length parameter, check if we received all the data
  991.         test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  992.         jz      @f
  993.         mov     eax, [ebp + http_msg.content_received]
  994.         cmp     eax, [ebp + http_msg.content_length]
  995.         jae     .got_all_data
  996.   @@:
  997.         cmp     [ebp + http_msg.buffer_length], 0
  998.         je      .buffer_full
  999.         ; Need more data
  1000.         popa
  1001.         xor     eax, eax
  1002.         dec     eax
  1003.         ret
  1004.  
  1005.   .buffer_full:
  1006.         test    [ebp + http_msg.flags], FLAG_STREAM
  1007.         jnz     .multibuff
  1008.         mov     eax, [ebp + http_msg.write_ptr]
  1009.         add     eax, BUFFERSIZE
  1010.         sub     eax, [ebp + http_msg.content_ptr]
  1011.         invoke  mem.realloc, [ebp + http_msg.content_ptr], eax
  1012.         or      eax, eax
  1013.         jz      .err_no_ram
  1014.         call    recalculate_pointers
  1015.         mov     [ebp + http_msg.buffer_length], BUFFERSIZE
  1016.         ; Need more data
  1017.         popa
  1018.         xor     eax, eax
  1019.         dec     eax
  1020.         ret
  1021.  
  1022.   .multibuff:
  1023.         ; This buffer is full
  1024.         popa
  1025.         xor     eax, eax
  1026.         ret
  1027.  
  1028.   .need_more_data_for_header:
  1029.         cmp     [ebp + http_msg.buffer_length], 0
  1030.         je      .err_header                     ; It's just too damn long!
  1031.         ; Need more data
  1032.         popa
  1033.         xor     eax, eax
  1034.         dec     eax
  1035.         ret
  1036.  
  1037.   .need_more_data_chunked:
  1038.         ; We only got a partial chunk, or need more chunks, update content_received and request more data
  1039.         add     [ebp + http_msg.content_received], eax
  1040.         popa
  1041.         xor     eax, eax
  1042.         dec     eax
  1043.         ret
  1044.  
  1045.   .got_all_data_chunked:
  1046.         ; Woohoo, we got all the chunked data, calculate total number of bytes received.
  1047.         mov     eax, [ebp + http_msg.chunk_ptr]
  1048.         sub     eax, [ebp + http_msg.content_ptr]
  1049.         mov     [ebp + http_msg.content_length], eax
  1050.         mov     [ebp + http_msg.content_received], eax
  1051.   .got_all_data:
  1052.         DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_received]
  1053.         or      [ebp + http_msg.flags], FLAG_GOT_ALL_DATA
  1054.         test    [ebp + http_msg.flags], FLAG_KEEPALIVE
  1055.         jnz     @f
  1056.         mcall   close, [ebp + http_msg.socket]
  1057.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  1058.   @@:
  1059.         popa
  1060.         xor     eax, eax
  1061.         ret
  1062.  
  1063. ;--------------------------------------------------------------
  1064. ;
  1065. ; error handeling code begins here
  1066. ;
  1067.  
  1068.   .check_socket:
  1069.         cmp     ebx, EWOULDBLOCK
  1070.         jne     .err_socket
  1071.         mcall   26, 9
  1072.         sub     eax, [ebp + http_msg.timestamp]
  1073.         cmp     eax, TIMEOUT
  1074.         ja      .err_timeout
  1075.         ; Need more data
  1076.         popa
  1077.         xor     eax, eax
  1078.         dec     eax
  1079.         ret
  1080.  
  1081.   .server_closed:
  1082.         DEBUGF  1, "server closed connection, transfer complete?\n"
  1083.         test    [ebp + http_msg.flags], FLAG_GOT_HEADER
  1084.         jz      .err_server_closed
  1085.         test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  1086.         jz      .got_all_data
  1087.   .err_server_closed:
  1088.         pop     eax
  1089.         DEBUGF  2, "ERROR: server closed connection unexpectedly\n"
  1090.         or      [ebp + http_msg.flags], FLAG_TRANSFER_FAILED
  1091.         jmp     .abort
  1092.  
  1093.   .err_header:
  1094.         pop     eax
  1095.         DEBUGF  2, "ERROR: invalid header\n"
  1096.         or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
  1097.         jmp     .abort
  1098.  
  1099.   .err_no_ram:
  1100.         DEBUGF  2, "ERROR: out of RAM\n"
  1101.         or      [ebp + http_msg.flags], FLAG_NO_RAM
  1102.         jmp     .abort
  1103.  
  1104.   .err_timeout:
  1105.         DEBUGF  2, "ERROR: timeout\n"
  1106.         or      [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR
  1107.         jmp     .abort
  1108.  
  1109.   .err_socket:
  1110.         DEBUGF  2, "ERROR: socket error %u\n", ebx
  1111.         or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
  1112.   .abort:
  1113.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  1114.         mcall   close, [ebp + http_msg.socket]
  1115.   .connection_closed:
  1116.         popa
  1117.         xor     eax, eax
  1118.         ret
  1119.  
  1120. endp
  1121.  
  1122.  
  1123. alloc_contentbuff:
  1124.  
  1125.         test    [ebp + http_msg.flags], FLAG_STREAM
  1126.         jz      @f
  1127.         mov     edx, BUFFERSIZE
  1128.   @@:
  1129.  
  1130. ; Allocate content buffer
  1131.         invoke  mem.alloc, edx
  1132.         or      eax, eax
  1133.         jz      .no_ram
  1134.  
  1135.         DEBUGF  1, "Content buffer allocated: 0x%x\n", eax
  1136.  
  1137. ; Copy already received content into content buffer
  1138.         mov     edi, eax
  1139.         lea     esi, [ebp + http_msg.http_header]
  1140.         add     esi, [ebp + http_msg.header_length]
  1141.         mov     ecx, [ebp + http_msg.write_ptr]
  1142.         sub     ecx, esi
  1143.         mov     ebx, ecx
  1144.         rep movsb
  1145.  
  1146. ; Update pointers to point to new buffer
  1147.         mov     [ebp + http_msg.content_ptr], eax
  1148.         mov     [ebp + http_msg.content_received], ebx
  1149.         sub     edx, ebx
  1150.         mov     [ebp + http_msg.buffer_length], edx
  1151.         add     eax, ebx
  1152.         mov     [ebp + http_msg.write_ptr], eax
  1153.  
  1154. ; Shrink header buffer
  1155.         mov     eax, http_msg.http_header
  1156.         add     eax, [ebp + http_msg.header_length]
  1157.         invoke  mem.realloc, ebp, eax
  1158.         or      eax, eax
  1159.   .no_ram:
  1160.  
  1161.         ret
  1162.  
  1163.  
  1164.  
  1165. recalculate_pointers:
  1166.  
  1167.         sub     eax, [ebp + http_msg.content_ptr]
  1168.         jz      .done
  1169.         add     [ebp + http_msg.content_ptr], eax
  1170.         add     [ebp + http_msg.write_ptr], eax
  1171.         add     [ebp + http_msg.chunk_ptr], eax
  1172.  
  1173.   .done:
  1174.         ret
  1175.  
  1176.  
  1177.  
  1178. ;;================================================================================================;;
  1179. proc HTTP_send identifier, dataptr, datalength ;//////////////////////////////////////////////////;;
  1180. ;;------------------------------------------------------------------------------------------------;;
  1181. ;? Send data to the server                                                                        ;;
  1182. ;;------------------------------------------------------------------------------------------------;;
  1183. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  1184. ;> dataptr      = pointer to data to be sent.                                                     ;;
  1185. ;> datalength   = length of data (in bytes) to be sent                                            ;;
  1186. ;;------------------------------------------------------------------------------------------------;;
  1187. ;< eax = number of bytes sent, -1 on error                                                        ;;
  1188. ;;================================================================================================;;
  1189.  
  1190.         push    ebx ecx edx esi edi
  1191.         mov     edx, [identifier]
  1192.         test    [edx + http_msg.flags], FLAG_CONNECTED
  1193.         jz      .fail
  1194.         mcall   send, [edx + http_msg.socket], [dataptr], [datalength], 0
  1195.         pop     edi esi edx ecx ebx
  1196.         ret
  1197.  
  1198.   .fail:
  1199.         pop     edi esi edx ecx ebx
  1200.         xor     eax, eax
  1201.         dec     eax
  1202.         ret
  1203.  
  1204. endp
  1205.  
  1206.  
  1207. ;;================================================================================================;;
  1208. proc HTTP_find_header_field identifier, headername ;//////////////////////////////////////////////;;
  1209. ;;------------------------------------------------------------------------------------------------;;
  1210. ;? Find a header field in the received HTTP header                                                ;;
  1211. ;?                                                                                                ;;
  1212. ;? NOTE: this function returns a pointer which points into the original header data.              ;;
  1213. ;? The header field is terminated by a CR, LF, space or maybe even tab.                           ;;
  1214. ;? A free operation should not be operated on this pointer!                                       ;;
  1215. ;;------------------------------------------------------------------------------------------------;;
  1216. ;> identifier   = ptr to http_msg struct                                                          ;;
  1217. ;> headername   = ptr to ASCIIZ string containing field you want to find (must be in lowercase)   ;;
  1218. ;;------------------------------------------------------------------------------------------------;;
  1219. ;< eax = 0 (error) / ptr to content of the HTTP header field                                      ;;
  1220. ;;================================================================================================;;
  1221.         push    ebx ecx edx esi edi
  1222.  
  1223.         DEBUGF  1, "Find header field: %s\n", [headername]
  1224.  
  1225.         mov     ebx, [identifier]
  1226.         test    [ebx + http_msg.flags], FLAG_GOT_HEADER
  1227.         jz      .fail
  1228.  
  1229.         lea     edx, [ebx + http_msg.http_header]
  1230.         mov     ecx, edx
  1231.         add     ecx, [ebx + http_msg.header_length]
  1232.  
  1233.   .restart:
  1234.         mov     esi, [headername]
  1235.         mov     edi, edx
  1236.   .loop:
  1237.         cmp     edi, ecx
  1238.         jae     .fail
  1239.         lodsb
  1240.         scasb
  1241.         je      .loop
  1242.         test    al, al
  1243.         jz      .done?
  1244.   .next:
  1245.         inc     edx
  1246.         jmp     .restart
  1247.  
  1248.   .not_done:
  1249.         inc     edi
  1250.   .done?:
  1251.         cmp     byte[edi-1], ':'
  1252.         je      .almost_done
  1253.         cmp     byte[edi-1], ' '
  1254.         je      .not_done
  1255.         cmp     byte[edi-1], 9  ; tab
  1256.         je      .not_done
  1257.  
  1258.         jmp     .next
  1259.  
  1260.   .almost_done:                 ; FIXME: buffer overflow?
  1261.         dec     edi
  1262.         DEBUGF  1, "Found header field\n"
  1263.   .spaceloop:
  1264.         inc     edi
  1265.         cmp     byte[edi], ' '
  1266.         je      .spaceloop
  1267.         cmp     byte[edi], 9    ; tab
  1268.         je      .spaceloop
  1269.  
  1270.         mov     eax, edi
  1271.         pop     edi esi edx ecx ebx
  1272.         ret
  1273.  
  1274.   .fail:
  1275.         DEBUGF  1, "Header field not found\n"
  1276.         pop     edi esi edx ecx ebx
  1277.         xor     eax, eax
  1278.         ret
  1279.  
  1280. endp
  1281.  
  1282.  
  1283.  
  1284. ;;================================================================================================;;
  1285. proc HTTP_escape URI, length ;////////////////////////////////////////////////////////////////////;;
  1286. ;;------------------------------------------------------------------------------------------------;;
  1287. ;?                                                                                                ;;
  1288. ;;------------------------------------------------------------------------------------------------;;
  1289. ;> URI = ptr to ASCIIZ URI/data                                                                   ;;
  1290. ;> length = length of URI/data                                                                    ;;
  1291. ;;------------------------------------------------------------------------------------------------;;
  1292. ;< eax = 0 (error) / ptr to ASCIIZ URI/data                                                       ;;
  1293. ;< ebx = length of escaped URI/data                                                               ;;
  1294. ;;================================================================================================;;
  1295.  
  1296.         DEBUGF  1, "HTTP_escape: %s\n", [URI]
  1297.  
  1298.         pusha
  1299.  
  1300.         invoke  mem.alloc, URLMAXLEN            ; FIXME: use length provided by caller to guess final size.
  1301.         test    eax, eax
  1302.         jz      .error
  1303.         mov     edx, URLMAXLEN-1                ; Remaining space in temp buffer minus one for 0 byte
  1304.         mov     [esp + 7 * 4], eax              ; return ptr in eax
  1305.         mov     esi, [URI]
  1306.         mov     edi, eax
  1307.         xor     ebx, ebx
  1308.         xor     ecx, ecx
  1309.   .loop:
  1310.         lodsb
  1311.         test    al, al
  1312.         jz      .done
  1313.  
  1314.         mov     cl, al
  1315.         and     cl, 0x1f
  1316.         mov     bl, al
  1317.         shr     bl, 3
  1318.         and     bl, not 3
  1319.         bt      dword[bits_must_escape + ebx], ecx
  1320.         jc      .escape
  1321.  
  1322.         stosb
  1323.         dec     edx
  1324.         jnz     .loop
  1325.         jmp     .out_of_space
  1326.  
  1327.   .escape:
  1328.         sub     edx, 3
  1329.         jbe     .out_of_space
  1330.         mov     al, '%'
  1331.         stosb
  1332.         mov     bl, byte[esi-1]
  1333.         shr     bl, 4
  1334.         mov     al, byte[str_hex + ebx]
  1335.         stosb
  1336.         mov     bl, byte[esi-1]
  1337.         and     bl, 0x0f
  1338.         mov     al, byte[str_hex + ebx]
  1339.         stosb
  1340.         jmp     .loop
  1341.  
  1342.  
  1343.   .out_of_space:
  1344.         DEBUGF  2, "ERROR: buffer too small!\n"
  1345.  
  1346.   .done:
  1347.         xor     al, al
  1348.         stosb
  1349.         sub     edi, [esp + 7 * 4]
  1350.         dec     edi
  1351.         mov     [esp + 4 * 4], edi
  1352.  
  1353.         popa
  1354.         DEBUGF  1, "escaped URL: %s\n", eax
  1355.         ret
  1356.  
  1357.   .error:
  1358.         DEBUGF  2, "ERROR: out of RAM!\n"
  1359.         popa
  1360.         xor     eax, eax
  1361.         ret
  1362.  
  1363. endp
  1364.  
  1365.  
  1366.  
  1367. ;;================================================================================================;;
  1368. proc HTTP_unescape URI, length ;//////////////////////////////////////////////////////////////////;;
  1369. ;;------------------------------------------------------------------------------------------------;;
  1370. ;?                                                                                                ;;
  1371. ;;------------------------------------------------------------------------------------------------;;
  1372. ;> URI = ptr to ASCIIZ URI                                                                        ;;
  1373. ;;------------------------------------------------------------------------------------------------;;
  1374. ;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
  1375. ;;================================================================================================;;
  1376.  
  1377.         DEBUGF  1, "HTTP_unescape: %s\n", [URI]
  1378.         pusha
  1379.  
  1380.         invoke  mem.alloc, URLMAXLEN            ; FIXME: use length provided by caller
  1381.         test    eax, eax
  1382.         jz      .error
  1383.         mov     edx, URLMAXLEN-1                ; Remaining space in temp buffer minus one for 0 byte
  1384.         mov     [esp + 7 * 4], eax              ; return ptr in eax
  1385.         mov     esi, [URI]
  1386.         mov     edi, eax
  1387.   .loop:
  1388.         lodsb
  1389.         test    al, al
  1390.         jz      .done
  1391.         cmp     al, '%'
  1392.         je      .unescape
  1393.         stosb
  1394.         dec     edx
  1395.         jnz     .loop
  1396.         jmp     .out_of_space
  1397.  
  1398.   .unescape:
  1399.         xor     ebx, ebx
  1400.         xor     ecx, ecx
  1401.   .unescape_nibble:
  1402.         lodsb
  1403.         sub     al, '0'
  1404.         jb      .fail
  1405.         cmp     al, 9
  1406.         jbe     .nibble_ok
  1407.         sub     al, 'A' - '0' - 10
  1408.         jb      .fail
  1409.         cmp     al, 15
  1410.         jbe     .nibble_ok
  1411.         sub     al, 'a' - 'A'
  1412.         cmp     al, 15
  1413.         ja      .fail
  1414.   .nibble_ok:
  1415.         shl     bl, 8
  1416.         or      bl, al
  1417.         dec     ecx
  1418.         jc      .unescape_nibble
  1419.         mov     al, bl
  1420.         stosb
  1421.         dec     edx
  1422.         jnz     .loop
  1423.         jmp     .out_of_space
  1424.  
  1425.   .fail:
  1426.         DEBUGF  2, "ERROR: invalid URI!\n"
  1427.         jmp     .loop
  1428.  
  1429.   .out_of_space:
  1430.         DEBUGF  2, "ERROR: buffer too small!\n"
  1431.  
  1432.   .done:
  1433.         xor     al, al
  1434.         stosb
  1435.         popa
  1436.         DEBUGF  1, "unescaped URL: %s\n", eax
  1437.         ret
  1438.  
  1439.   .error:
  1440.         DEBUGF  2, "ERROR: out of RAM!\n"
  1441.         popa
  1442.         xor     eax, eax
  1443.         ret
  1444.  
  1445. endp
  1446.  
  1447.  
  1448.  
  1449.  
  1450.  
  1451. ;;================================================================================================;;
  1452. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1453. ;;================================================================================================;;
  1454. ;! Internal procedures section                                                                    ;;
  1455. ;;                                                                                                ;;
  1456. ;; NOTICE: These procedures do not follow stdcall conventions and thus may destroy any register.  ;;
  1457. ;;================================================================================================;;
  1458. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1459. ;;================================================================================================;;
  1460.  
  1461.  
  1462.  
  1463.  
  1464. ;;================================================================================================;;
  1465. proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
  1466. ;;------------------------------------------------------------------------------------------------;;
  1467. ;? Connects to a HTTP server                                                                      ;;
  1468. ;;------------------------------------------------------------------------------------------------;;
  1469. ;> hostname     = ptr to ASCIIZ hostname                                                          ;;
  1470. ;> port         = port (x86 byte order)                                                           ;;
  1471. ;;------------------------------------------------------------------------------------------------;;
  1472. ;< eax = 0 (error) / socketnum                                                                    ;;
  1473. ;;================================================================================================;;
  1474.  
  1475. locals
  1476.         sockaddr        dd ?
  1477.         socketnum       dd ?
  1478. endl
  1479.  
  1480.         cmp     [proxyAddr], 0
  1481.         je      .no_proxy
  1482.  
  1483.         mov     [hostname], proxyAddr
  1484.  
  1485.         push    [proxyPort]
  1486.         pop     [port]
  1487.   .no_proxy:
  1488.  
  1489. ; Resolve the hostname
  1490.         DEBUGF  1, "Resolving hostname\n"
  1491.         push    esp     ; reserve stack place
  1492.         invoke  getaddrinfo, [hostname], 0, 0, esp
  1493.         pop     esi
  1494.         test    eax, eax
  1495.         jnz     .error1
  1496.  
  1497. ; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
  1498.         push    esi     ; for freeaddrinfo
  1499.         mov     esi, [esi + addrinfo.ai_addr]
  1500.         mov     [sockaddr], esi
  1501.         mov     eax, [esi + sockaddr_in.sin_addr]
  1502.         test    eax, eax
  1503.         jz      .error2
  1504.  
  1505.         DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
  1506.         [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
  1507.         [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
  1508.  
  1509.         mov     [esi + sockaddr_in.sin_family], AF_INET4
  1510.         mov     eax, [port]
  1511.         xchg    al, ah
  1512.         mov     [esi + sockaddr_in.sin_port], ax
  1513.  
  1514. ; Open a new TCP socket
  1515.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  1516.         test    eax, eax
  1517.         jz      .error3
  1518.         mov     [socketnum], eax
  1519.         DEBUGF  1, "Socket: 0x%x\n", eax
  1520.  
  1521. ; Connect to the server
  1522.         mcall   connect, [socketnum], [sockaddr], 18
  1523.         test    eax, eax
  1524.         jnz     .error3
  1525.         DEBUGF  1, "Socket is now connected.\n"
  1526.  
  1527.         invoke  freeaddrinfo            ; Free allocated memory
  1528.         mov     eax, [socketnum]
  1529.         ret
  1530.  
  1531.   .error3:
  1532.         DEBUGF  2, "Could not connect to the remote server\n"
  1533.         invoke  freeaddrinfo            ; Free allocated memory
  1534.         xor     eax, eax
  1535.         ret
  1536.  
  1537.   .error2:
  1538.         DEBUGF  2, "Resolving hostname failed\n"
  1539.         invoke  freeaddrinfo            ; Free allocated memory
  1540.         xor     eax, eax
  1541.         ret
  1542.  
  1543.   .error1:
  1544.         DEBUGF  2, "Contacting DNS server failed with EAI code: %x\n", eax
  1545.         xor     eax, eax
  1546.         ret
  1547.  
  1548. endp
  1549.  
  1550.  
  1551. ;;================================================================================================;;
  1552. proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
  1553. ;;------------------------------------------------------------------------------------------------;;
  1554. ;? Split a given URL into hostname and pageaddr                                                   ;;
  1555. ;;------------------------------------------------------------------------------------------------;;
  1556. ;> URL = ptr to ASCIIZ URL                                                                        ;;
  1557. ;;------------------------------------------------------------------------------------------------;;
  1558. ;< eax = 0 (error) / ptr to ASCIIZ hostname                                                       ;;
  1559. ;< ebx = ptr to ASCIIZ pageaddr                                                                   ;;
  1560. ;< ecx = port number                                                                              ;;
  1561. ;;================================================================================================;;
  1562.  
  1563. locals
  1564.         urlsize         dd ?
  1565.         hostname        dd ?
  1566.         pageaddr        dd ?
  1567.         port            dd ?
  1568. endl
  1569.  
  1570.         DEBUGF  1, "parsing URL: %s\n", [URL]
  1571.  
  1572. ; remove any leading protocol text
  1573.         mov     edi, [URL]
  1574.         mov     ecx, URLMAXLEN
  1575.         mov     ax, '//'
  1576.   .loop1:
  1577.         cmp     byte[edi], 0            ; end of URL?
  1578.         je      .url_ok                 ; yep, so not found
  1579.         cmp     [edi], ax
  1580.         je      .skip_proto
  1581.         inc     edi
  1582.         dec     ecx
  1583.         jnz     .loop1
  1584.         jmp     .invalid
  1585.  
  1586.   .skip_proto:
  1587.         inc     edi                     ; skip the two '/'
  1588.         inc     edi
  1589.         mov     [URL], edi              ; update pointer so it skips protocol
  1590.  
  1591. ; Find the trailing 0 byte
  1592.         xor     al, al
  1593.         repne   scasb
  1594.         jne     .invalid                ; ecx reached 0 before we reached end of string
  1595.  
  1596.   .url_ok:
  1597.         sub     edi, [URL]              ; calculate total length of URL
  1598.         mov     [urlsize], edi
  1599.  
  1600. ; now look for page delimiter - it's a '/' character
  1601.         mov     ecx, edi                ; URL length
  1602.         mov     edi, [URL]
  1603.         mov     al, '/'
  1604.         repne   scasb
  1605.         jne     @f
  1606.         dec     edi                     ; return one char, '/' must be part of the pageaddr
  1607.         inc     ecx                     ;
  1608.   @@:
  1609.         push    ecx edi                 ; remember the pointer and length of pageaddr
  1610.  
  1611.  
  1612. ; Create new buffer and put hostname in it.
  1613.         mov     ecx, edi
  1614.         sub     ecx, [URL]
  1615.         inc     ecx                     ; we will add a 0 byte at the end
  1616.         invoke  mem.alloc, ecx
  1617.         or      eax, eax
  1618.         jz      .no_mem
  1619.  
  1620.         mov     [hostname], eax         ; copy hostname to buffer
  1621.         mov     edi, eax
  1622.         mov     esi, [URL]
  1623.         dec     ecx
  1624.         rep     movsb
  1625.         xor     al, al
  1626.         stosb
  1627.  
  1628. ; Check if user provided a port, and convert it if so.
  1629.         mov     esi, [hostname]
  1630.         mov     [port], 80              ; default port if user didnt provide one
  1631.   .portloop:
  1632.         lodsb
  1633.         test    al, al
  1634.         jz      .no_port
  1635.         cmp     al, ':'
  1636.         jne     .portloop
  1637.  
  1638.         push    esi
  1639.         call    ascii_dec_ebx
  1640.         pop     edi
  1641.         cmp     byte[esi-1], 0
  1642.         jne     .invalid
  1643.         cmp     [proxyAddr], 0          ; remove port number from hostname
  1644.         jne     @f                      ; unless when we are using proxy
  1645.         mov     byte[edi-1], 0
  1646.   @@:
  1647.         test    ebx, ebx
  1648.         je      .invalid
  1649.         cmp     ebx, 0xffff
  1650.         ja      .invalid
  1651.         mov     [port], ebx
  1652.   .no_port:
  1653.  
  1654.  
  1655. ; Did user provide a pageaddr?
  1656.         mov     [pageaddr], str_slash   ; assume there is no pageaddr
  1657.         pop     esi ecx
  1658.         test    ecx, ecx
  1659.         jz      .no_page
  1660.  
  1661. ; Create new buffer and put pageaddr into it.
  1662.         inc     ecx                     ; we will add a 0 byte at the end
  1663.         invoke  mem.alloc, ecx
  1664.         or      eax, eax
  1665.         jz      .no_mem
  1666.  
  1667.         mov     [pageaddr], eax         ; copy pageaddr to buffer
  1668.         mov     edi, eax
  1669.         dec     ecx
  1670.         rep     movsb
  1671.         xor     al, al
  1672.         stosb
  1673.  
  1674.   .no_page:
  1675.         mov     eax, [hostname]
  1676.         mov     ebx, [pageaddr]
  1677.         mov     ecx, [port]
  1678.  
  1679.         DEBUGF  1, "hostname: %s\n", eax
  1680.         DEBUGF  1, "pageaddr: %s\n", ebx
  1681.         DEBUGF  1, "port: %u\n", ecx
  1682.  
  1683.         ret
  1684.  
  1685.   .no_mem:
  1686.         DEBUGF  2, "Out of memory!\n"
  1687.         xor     eax, eax
  1688.         ret
  1689.  
  1690.   .invalid:
  1691.         DEBUGF  2, "Invalid URL!\n"
  1692.         xor     eax, eax
  1693.         ret
  1694.  
  1695. endp
  1696.  
  1697.  
  1698.  
  1699.  
  1700.  
  1701. ;;================================================================================================;;
  1702. proc append_proxy_auth_header ;///////////////////////////////////////////////////////////////////;;
  1703. ;;------------------------------------------------------------------------------------------------;;
  1704. ;? Appends the proxy authentication header                                                        ;;
  1705. ;;------------------------------------------------------------------------------------------------;;
  1706. ;> /                                                                                              ;;
  1707. ;;------------------------------------------------------------------------------------------------;;
  1708. ;< /                                                                                              ;;
  1709. ;;================================================================================================;;
  1710.         mov     esi, str_proxy_auth
  1711.         mov     ecx, str_proxy_auth.length
  1712.         rep     movsb
  1713. ; base64-encode string <user>:<password>
  1714.         mov     esi, proxyUser
  1715.  
  1716. apah000:
  1717.         lodsb
  1718.         test    al, al
  1719.         jz      apah001
  1720.         call    encode_base64_byte
  1721.         jmp     apah000
  1722.  
  1723. apah001:
  1724.         mov     al, ':'
  1725.         call    encode_base64_byte
  1726.         mov     esi, proxyPassword
  1727.  
  1728. apah002:
  1729.         lodsb
  1730.         test    al, al
  1731.         jz      apah003
  1732.         call    encode_base64_byte
  1733.         jmp     apah002
  1734.  
  1735. apah003:
  1736.         call    encode_base64_final
  1737.         ret
  1738.  
  1739. encode_base64_byte:
  1740.         inc     ecx
  1741.         shl     edx, 8
  1742.         mov     dl, al
  1743.         cmp     ecx, 3
  1744.         je      ebb001
  1745.         ret
  1746.  
  1747. ebb001:
  1748.         shl     edx, 8
  1749.         inc     ecx
  1750.  
  1751. ebb002:
  1752.         rol     edx, 6
  1753.         xor     eax, eax
  1754.         xchg    al, dl
  1755.         mov     al, [base64_table+eax]
  1756.         stosb
  1757.         loop    ebb002
  1758.         ret
  1759.  
  1760. encode_base64_final:
  1761.         mov     al, 0
  1762.         test    ecx, ecx
  1763.         jz      ebf000
  1764.         call    encode_base64_byte
  1765.         test    ecx, ecx
  1766.         jz      ebf001
  1767.         call    encode_base64_byte
  1768.         mov     byte [edi-2], '='
  1769.  
  1770. ebf001:
  1771.         mov     byte [edi-1], '='
  1772.  
  1773. ebf000:
  1774.         ret
  1775.  
  1776. endp
  1777.  
  1778.  
  1779. ;;================================================================================================;;
  1780. proc eax_ascii_dec ;//////////////////////////////////////////////////////////////////////////////;;
  1781. ;;------------------------------------------------------------------------------------------------;;
  1782. ;? Convert eax to ASCII decimal number                                                            ;;
  1783. ;;------------------------------------------------------------------------------------------------;;
  1784. ;> eax = number                                                                                   ;;
  1785. ;> edi = ptr where to write ASCII decimal number                                                  ;;
  1786. ;;------------------------------------------------------------------------------------------------;;
  1787. ;< /                                                                                              ;;
  1788. ;;================================================================================================;;
  1789.  
  1790.         push    -'0'
  1791.         mov     ecx, 10
  1792.   .loop:
  1793.         xor     edx, edx
  1794.         div     ecx
  1795.         push    edx
  1796.         test    eax, eax
  1797.         jnz     .loop
  1798.  
  1799.   .loop2:
  1800.         pop     eax
  1801.         add     al, '0'
  1802.         jz      .done
  1803.         stosb
  1804.         jmp     .loop2
  1805.   .done:
  1806.  
  1807.         ret
  1808.  
  1809. endp
  1810.  
  1811.  
  1812. ;;================================================================================================;;
  1813. proc ascii_dec_ebx ;//////////////////////////////////////////////////////////////////////////////;;
  1814. ;;------------------------------------------------------------------------------------------------;;
  1815. ;? Convert ASCII decimal number to ebx                                                            ;;
  1816. ;;------------------------------------------------------------------------------------------------;;
  1817. ;> esi = ptr where to read ASCII decimal number                                                   ;;
  1818. ;;------------------------------------------------------------------------------------------------;;
  1819. ;> ebx = number                                                                                   ;;
  1820. ;;================================================================================================;;
  1821.  
  1822.         xor     eax, eax
  1823.         xor     ebx, ebx
  1824.   .loop:
  1825.         lodsb
  1826.         sub     al, '0'
  1827.         jb      .done
  1828.         cmp     al, 9
  1829.         ja      .done
  1830.         lea     ebx, [ebx + 4*ebx]
  1831.         shl     ebx, 1
  1832.         add     ebx, eax
  1833.         jmp     .loop
  1834.   .done:
  1835.  
  1836.         ret
  1837.  
  1838. endp
  1839.  
  1840.  
  1841. ;;================================================================================================;;
  1842. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1843. ;;================================================================================================;;
  1844. ;! Imported functions section                                                                     ;;
  1845. ;;================================================================================================;;
  1846. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1847. ;;================================================================================================;;
  1848.  
  1849.  
  1850. align 16
  1851. @IMPORT:
  1852.  
  1853. library \
  1854.         libini, 'libini.obj', \
  1855.         network, 'network.obj'
  1856.  
  1857. import  libini, \
  1858.         ini.get_str, 'ini_get_str', \
  1859.         ini.get_int, 'ini_get_int'
  1860.  
  1861. import  network,\
  1862.         getaddrinfo, 'getaddrinfo',\
  1863.         freeaddrinfo,  'freeaddrinfo',\
  1864.         inet_ntoa, 'inet_ntoa'
  1865.  
  1866. ;;===========================================================================;;
  1867. ;;///////////////////////////////////////////////////////////////////////////;;
  1868. ;;===========================================================================;;
  1869. ;! Exported functions section                                                ;;
  1870. ;;===========================================================================;;
  1871. ;;///////////////////////////////////////////////////////////////////////////;;
  1872. ;;===========================================================================;;
  1873.  
  1874.  
  1875. HTTP_stop = HTTP_disconnect
  1876. HTTP_process = HTTP_receive
  1877.  
  1878. align 4
  1879. @EXPORT:
  1880. export  \
  1881.         lib_init                , 'lib_init'            , \
  1882.         0x00010001              , 'version'             , \
  1883.         HTTP_get                , 'get'                 , \
  1884.         HTTP_head               , 'head'                , \
  1885.         HTTP_post               , 'post'                , \
  1886.         HTTP_find_header_field  , 'find_header_field'   , \
  1887.         HTTP_process            , 'process'             , \    ; To be removed
  1888.         HTTP_send               , 'send'                , \
  1889.         HTTP_receive            , 'receive'             , \
  1890.         HTTP_disconnect         , 'disconnect'          , \
  1891.         HTTP_free               , 'free'                , \
  1892.         HTTP_stop               , 'stop'                , \    ; To be removed
  1893.         HTTP_escape             , 'escape'              , \
  1894.         HTTP_unescape           , 'unescape'
  1895. ;        HTTP_put                , 'put'                 , \
  1896. ;        HTTP_delete             , 'delete'              , \
  1897. ;        HTTP_trace              , 'trace'               , \
  1898. ;        HTTP_connect            , 'connect'             , \
  1899.  
  1900.  
  1901.  
  1902. section '.data' data readable writable align 16
  1903.  
  1904. inifile         db '/sys/settings/network.ini', 0
  1905.  
  1906. sec_proxy:
  1907. key_proxy       db 'proxy', 0
  1908. key_proxyport   db 'port', 0
  1909. key_user        db 'user', 0
  1910. key_password    db 'password', 0
  1911.  
  1912. str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
  1913.   .length       = $ - str_http11
  1914. str_post_cl     db 13, 10, 'Content-Length: '
  1915.   .length       = $ - str_post_cl
  1916. str_post_ct     db 13, 10, 'Content-Type: '
  1917.   .length       = $ - str_post_ct
  1918. str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
  1919.   .length       = $ - str_proxy_auth
  1920. str_close       db 'User-Agent: KolibriOS libHTTP/1.1', 13, 10, 'Connection: close', 13, 10, 13, 10
  1921.   .length       = $ - str_close
  1922. str_keep        db 'User-Agent: KolibriOS libHTTP/1.1', 13, 10, 'Connection: keep-alive', 13, 10, 13, 10
  1923.   .length       = $ - str_keep
  1924.  
  1925. str_http        db 'http://', 0
  1926.  
  1927. base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  1928.                 db '0123456789+/'
  1929.  
  1930. str_cl          db 'content-length', 0
  1931. str_slash       db '/', 0
  1932. str_te          db 'transfer-encoding', 0
  1933. str_get         db 'GET ', 0
  1934. str_head        db 'HEAD ', 0
  1935. str_post        db 'POST ', 0
  1936.  
  1937. bits_must_escape:
  1938. dd      0xffffffff                                                      ; 00-1F
  1939. dd      1 shl 0 + 1 shl 2 + 1 shl 3 + 1 shl 5 + 1 shl 28 + 1 shl 30     ; "#%<>
  1940. dd      1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 30                       ;[\]^
  1941. dd      1 shl 0 + 1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 31             ;`{|} DEL
  1942.  
  1943. dd      0xffffffff
  1944. dd      0xffffffff
  1945. dd      0xffffffff
  1946. dd      0xffffffff
  1947.  
  1948. str_hex:
  1949. db '0123456789ABCDEF'
  1950.  
  1951. include_debug_strings
  1952.  
  1953. ; uninitialized data
  1954. mem.alloc       dd ?
  1955. mem.free        dd ?
  1956. mem.realloc     dd ?
  1957. dll.load        dd ?
  1958.  
  1959. proxyAddr       rb 256
  1960. proxyUser       rb 256
  1961. proxyPassword   rb 256
  1962. proxyPort       dd ?