Subversion Repositories Kolibri OS

Rev

Rev 8023 | Rev 8571 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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