Subversion Repositories Kolibri OS

Rev

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