Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2013. 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. ;;                                                                 ;;
  10. ;;         GNU GENERAL PUBLIC LICENSE                              ;;
  11. ;;          Version 2, June 1991                                   ;;
  12. ;;                                                                 ;;
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14.  
  15. ; references:
  16. ; "HTTP made really easy", http://www.jmarshall.com/easy/http/
  17. ; "Hypertext Transfer Protocol -- HTTP/1.1", http://tools.ietf.org/html/rfc2616
  18.  
  19.  
  20.         URLMAXLEN       = 65535
  21.         BUFFERSIZE      = 4096
  22.         TIMEOUT         = 1000  ; in 1/100 s
  23.  
  24.         __DEBUG__       = 1
  25.         __DEBUG_LEVEL__ = 1
  26.  
  27.  
  28. format MS COFF
  29.  
  30. public @EXPORT as 'EXPORTS'
  31.  
  32. include '../../../struct.inc'
  33. include '../../../proc32.inc'
  34. include '../../../macros.inc'
  35. purge section,mov,add,sub
  36. include '../../../debug-fdo.inc'
  37.  
  38. include '../../../network.inc'
  39. include 'http.inc'
  40.  
  41. virtual at 0
  42.         http_msg http_msg
  43. end virtual
  44.  
  45. macro copy_till_zero {
  46.   @@:
  47.         lodsb
  48.         test    al, al
  49.         jz      @f
  50.         stosb
  51.         jmp     @r
  52.   @@:
  53. }
  54.  
  55. macro HTTP_init_buffer buffer, socketnum {
  56.  
  57.         mov     eax, buffer
  58.         push    socketnum
  59.         popd    [eax + http_msg.socket]
  60.         lea     esi, [eax + http_msg.data]
  61.         mov     [eax + http_msg.flags], FLAG_CONNECTED
  62.         mov     [eax + http_msg.write_ptr], esi
  63.         mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.data
  64.         mov     [eax + http_msg.chunk_ptr], 0
  65.  
  66.         mov     [eax + http_msg.status], 0
  67.         mov     [eax + http_msg.header_length], 0
  68.         mov     [eax + http_msg.content_length], 0
  69.         mov     [eax + http_msg.content_received], 0
  70.  
  71.         push    eax ebp
  72.         mov     ebp, eax
  73.         mcall   29, 9
  74.         mov     [ebp + http_msg.timestamp], eax
  75.         pop     ebp eax
  76. }
  77.  
  78. section '.flat' code readable align 16
  79.  
  80. ;;===========================================================================;;
  81. lib_init: ;//////////////////////////////////////////////////////////////////;;
  82. ;;---------------------------------------------------------------------------;;
  83. ;? Library entry point (called after library load)                           ;;
  84. ;;---------------------------------------------------------------------------;;
  85. ;> eax = pointer to memory allocation routine                                ;;
  86. ;> ebx = pointer to memory freeing routine                                   ;;
  87. ;> ecx = pointer to memory reallocation routine                              ;;
  88. ;> edx = pointer to library loading routine                                  ;;
  89. ;;---------------------------------------------------------------------------;;
  90. ;< eax = 1 (fail) / 0 (ok)                                                   ;;
  91. ;;===========================================================================;;
  92.         mov     [mem.alloc], eax
  93.         mov     [mem.free], ebx
  94.         mov     [mem.realloc], ecx
  95.         mov     [dll.load], edx
  96.  
  97.         invoke  dll.load, @IMPORT
  98.         test    eax, eax
  99.         jnz     .error
  100.  
  101. ; load proxy settings
  102.         pusha
  103.         invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
  104.         invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
  105.         mov     [proxyPort], eax
  106.         invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
  107.         invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
  108.         popa
  109.  
  110.         DEBUGF  1, "HTTP library: init OK\n"
  111.  
  112.         xor     eax, eax
  113.         ret
  114.  
  115.   .error:
  116.         DEBUGF  1, "ERROR loading libraries\n"
  117.  
  118.         xor     eax, eax
  119.         inc     eax
  120.  
  121.         ret
  122.  
  123.  
  124.  
  125.  
  126. ;;================================================================================================;;
  127. proc HTTP_get URL, add_header ;///////////////////////////////////////////////////////////////////;;
  128. ;;------------------------------------------------------------------------------------------------;;
  129. ;? Initiates a HTTP connection, using 'GET' method.                                               ;;
  130. ;;------------------------------------------------------------------------------------------------;;
  131. ;> URL          = pointer to ASCIIZ URL                                                           ;;
  132. ;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
  133. ;;------------------------------------------------------------------------------------------------;;
  134. ;< eax = 0 (error) / buffer ptr                                                                   ;;
  135. ;;================================================================================================;;
  136. locals
  137.         hostname        dd ?
  138.         pageaddr        dd ?
  139.         sockaddr        dd ?
  140.         socketnum       dd ?
  141.         buffer          dd ?
  142.         port            dd ?
  143. endl
  144.  
  145.         pusha
  146.  
  147. ; split the URL into hostname and pageaddr
  148.         stdcall parse_url, [URL]
  149.         test    eax, eax
  150.         jz      .error
  151.         mov     [hostname], eax
  152.         mov     [pageaddr], ebx
  153.         mov     [port], ecx
  154.  
  155. ; Do we need to use a proxy?
  156.         cmp     [proxyAddr], 0
  157.         jne     .proxy_done
  158.  
  159.   .proxy_done:
  160.  
  161. ;;;;
  162.  
  163. ; Connect to the other side.
  164.         stdcall open_connection, [hostname], [port]
  165.         test    eax, eax
  166.         jz      .error
  167.         mov     [socketnum], eax
  168.  
  169. ; Create the HTTP request.
  170.         invoke  mem.alloc, BUFFERSIZE
  171.         test    eax, eax
  172.         jz      .error
  173.         mov     [buffer], eax
  174.         mov     edi, eax
  175.         DEBUGF  1, "Buffer has been allocated.\n"
  176.  
  177.         mov     esi, str_get
  178.         copy_till_zero
  179.  
  180.         mov     esi, [pageaddr]
  181.         copy_till_zero
  182.  
  183.         mov     esi, str_http11
  184.         mov     ecx, str_http11.length
  185.         rep     movsb
  186.  
  187.         mov     esi, [hostname]
  188.         copy_till_zero
  189.  
  190.         mov     esi, [add_header]
  191.         test    esi, esi
  192.         jz      @f
  193.         copy_till_zero
  194.   @@:
  195.  
  196.         mov     esi, str_close
  197.         mov     ecx, str_close.length
  198.         rep     movsb
  199.  
  200.         mov     byte[edi], 0
  201.         DEBUGF  1, "Request:\n%s", [buffer]
  202.  
  203. ; Free unused memory
  204.         push    edi
  205.         invoke  mem.free, [pageaddr]
  206.         invoke  mem.free, [hostname]
  207.         pop     esi
  208.  
  209. ; Send the request
  210.         sub     esi, [buffer]   ; length
  211.         xor     edi, edi        ; flags
  212.         mcall   send, [socketnum], [buffer]
  213.         test    eax, eax
  214.         jz      .error
  215.         DEBUGF  1, "Request has been sent to server.\n"
  216.  
  217.         HTTP_init_buffer [buffer], [socketnum]
  218.  
  219.         popa
  220.         mov     eax, [buffer]   ; return buffer ptr
  221.         ret
  222.  
  223.   .error:
  224.         DEBUGF  1, "Error!\n"
  225.         popa
  226.         xor     eax, eax        ; return 0 = error
  227.         ret
  228.  
  229. endp
  230.  
  231.  
  232.  
  233. ;;================================================================================================;;
  234. proc HTTP_head URL, add_header ;//////////////////////////////////////////////////////////////////;;
  235. ;;------------------------------------------------------------------------------------------------;;
  236. ;? Initiates a HTTP connection, using 'HEAD' method.                                              ;;
  237. ;;------------------------------------------------------------------------------------------------;;
  238. ;> URL          = pointer to ASCIIZ URL                                                           ;;
  239. ;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
  240. ;;------------------------------------------------------------------------------------------------;;
  241. ;< eax = 0 (error) / buffer ptr                                                                   ;;
  242. ;;================================================================================================;;
  243. locals
  244.         hostname        dd ?
  245.         pageaddr        dd ?
  246.         sockaddr        dd ?
  247.         socketnum       dd ?
  248.         buffer          dd ?
  249.         port            dd ?
  250. endl
  251.  
  252.         pusha
  253. ; split the URL into hostname and pageaddr
  254.         stdcall parse_url, [URL]
  255.         test    eax, eax
  256.         jz      .error
  257.         mov     [hostname], eax
  258.         mov     [pageaddr], ebx
  259.         mov     [port], ecx
  260.  
  261. ; Do we need to use a proxy?
  262.         cmp     [proxyAddr], 0
  263.         jne     .proxy_done
  264.  
  265.         ; TODO: set hostname to that of the
  266.   .proxy_done:
  267.  
  268. ;;;;
  269.  
  270. ; Connect to the other side.
  271.         stdcall open_connection, [hostname], [port]
  272.         test    eax, eax
  273.         jz      .error
  274.         mov     [socketnum], eax
  275.  
  276. ; Create the HTTP request.
  277.         invoke  mem.alloc, BUFFERSIZE
  278.         test    eax, eax
  279.         jz      .error
  280.         mov     [buffer], eax
  281.         mov     edi, eax
  282.         DEBUGF  1, "Buffer has been allocated.\n"
  283.  
  284.         mov     esi, str_head
  285.         copy_till_zero
  286.  
  287.         mov     esi, [pageaddr]
  288.         copy_till_zero
  289.  
  290.         mov     esi, str_http11
  291.         mov     ecx, str_http11.length
  292.         rep     movsb
  293.  
  294.         mov     esi, [hostname]
  295.         copy_till_zero
  296.  
  297.         mov     esi, [add_header]
  298.         test    esi, esi
  299.         jz      @f
  300.         copy_till_zero
  301.   @@:
  302.  
  303.         mov     esi, str_close
  304.         mov     ecx, str_close.length
  305.         rep     movsb
  306.  
  307.         mov     byte[edi], 0
  308.         DEBUGF  1, "Request:\n%s", [buffer]
  309.  
  310.  
  311. ; Free unused memory
  312.         push    edi
  313.         invoke  mem.free, [pageaddr]
  314.         invoke  mem.free, [hostname]
  315.         pop     esi
  316.  
  317. ; Send the request
  318.         sub     esi, [buffer]   ; length
  319.         xor     edi, edi        ; flags
  320.         mcall   send, [socketnum], [buffer]
  321.         test    eax, eax
  322.         jz      .error
  323.         DEBUGF  1, "Request has been sent to server.\n"
  324.  
  325.         HTTP_init_buffer [buffer], [socketnum]
  326.  
  327.         popa
  328.         mov     eax, [buffer]
  329.         ret                     ; return buffer ptr
  330.  
  331.   .error:
  332.         DEBUGF  1, "Error!\n"
  333.         popa
  334.         xor     eax, eax        ; return 0 = error
  335.         ret
  336.  
  337. endp
  338.  
  339.  
  340. ;;================================================================================================;;
  341. proc HTTP_post URL, add_header, content_type, content_length ;////////////////////////////////////;;
  342. ;;------------------------------------------------------------------------------------------------;;
  343. ;? Initiates a HTTP connection, using 'GET' method.                                               ;;
  344. ;;------------------------------------------------------------------------------------------------;;
  345. ;> URL                  = pointer to ASCIIZ URL                                                   ;;
  346. ;> add_header           = pointer to additional header parameters (ASCIIZ), or null for none.     ;;
  347. ;> content_type         = pointer to ASCIIZ string containing content type                        ;;
  348. ;> content_length       = length of content (in bytes)                                            ;;
  349. ;;------------------------------------------------------------------------------------------------;;
  350. ;< eax = 0 (error) / buffer ptr                                                                   ;;
  351. ;;================================================================================================;;
  352. locals
  353.         hostname        dd ?
  354.         pageaddr        dd ?
  355.         sockaddr        dd ?
  356.         socketnum       dd ?
  357.         buffer          dd ?
  358.         port            dd ?
  359. endl
  360.  
  361.         pusha
  362. ; split the URL into hostname and pageaddr
  363.         stdcall parse_url, [URL]
  364.         test    eax, eax
  365.         jz      .error
  366.         mov     [hostname], eax
  367.         mov     [pageaddr], ebx
  368.         mov     [port], ecx
  369.  
  370. ; Do we need to use a proxy?
  371.         cmp     [proxyAddr], 0
  372.         jne     .proxy_done
  373.  
  374.         ; TODO: set hostname to that of the
  375.   .proxy_done:
  376.  
  377. ;;;;
  378.  
  379. ; Connect to the other side.
  380.         stdcall open_connection, [hostname], [port]
  381.         test    eax, eax
  382.         jz      .error
  383.         mov     [socketnum], eax
  384.  
  385. ; Create the HTTP request.
  386.         invoke  mem.alloc, BUFFERSIZE
  387.         test    eax, eax
  388.         jz      .error
  389.         mov     [buffer], eax
  390.         mov     edi, eax
  391.         DEBUGF  1, "Buffer has been allocated.\n"
  392.  
  393.         mov     esi, str_post
  394.         copy_till_zero
  395.  
  396.         mov     esi, [pageaddr]
  397.         copy_till_zero
  398.  
  399.         mov     esi, str_http11
  400.         mov     ecx, str_http11.length
  401.         rep     movsb
  402.  
  403.         mov     esi, [hostname]
  404.         copy_till_zero
  405.  
  406.         mov     esi, str_post_cl
  407.         mov     ecx, str_post_cl.length
  408.         rep     movsb
  409.  
  410.         mov     eax, [content_length]
  411.         call    ascii_dec
  412.  
  413.         mov     esi, str_post_ct
  414.         mov     ecx, str_post_ct.length
  415.         rep     movsb
  416.  
  417.         mov     esi, [content_type]
  418.         copy_till_zero
  419.  
  420.         mov     esi, [add_header]
  421.         test    esi, esi
  422.         jz      @f
  423.         copy_till_zero
  424.   @@:
  425.  
  426.         mov     esi, str_close
  427.         mov     ecx, str_close.length
  428.         rep     movsb
  429.  
  430.         mov     byte[edi], 0
  431.         DEBUGF  1, "Request:\n%s", [buffer]
  432.  
  433. ; Free unused memory
  434.         push    edi
  435.         invoke  mem.free, [pageaddr]
  436.         invoke  mem.free, [hostname]
  437.         pop     esi
  438.  
  439. ; Send the request
  440.         sub     esi, [buffer]   ; length
  441.         xor     edi, edi        ; flags
  442.         mcall   send, [socketnum], [buffer]
  443.         test    eax, eax
  444.         jz      .error
  445.         DEBUGF  1, "Request has been sent to server.\n"
  446.  
  447.         HTTP_init_buffer [buffer], [socketnum]
  448.  
  449.         popa
  450.         mov     eax, [buffer]
  451.         ret                     ; return buffer ptr
  452.  
  453.   .error:
  454.         DEBUGF  1, "Error!\n"
  455.         popa
  456.         xor     eax, eax        ; return 0 = error
  457.         ret
  458.  
  459. endp
  460.  
  461.  
  462.  
  463. ;;================================================================================================;;
  464. proc HTTP_process identifier ;////////////////////////////////////////////////////////////////////;;
  465. ;;------------------------------------------------------------------------------------------------;;
  466. ;? Receive data from the server, parse headers and put data in receive buffer.                    ;;
  467. ;? To complete a transfer, this procedure must be called over and over again untill it returns 0. ;;
  468. ;;------------------------------------------------------------------------------------------------;;
  469. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  470. ;;------------------------------------------------------------------------------------------------;;
  471. ;< eax = -1 (not finished) / 0 finished                                                           ;;
  472. ;;================================================================================================;;
  473.         pusha
  474.         mov     ebp, [identifier]
  475.  
  476. ; If the connection is closed, return immediately
  477.         test    [ebp + http_msg.flags], FLAG_CONNECTED
  478.         jz      .connection_closed
  479.  
  480. ; Receive some data
  481.         mcall   recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
  482.                       [ebp + http_msg.buffer_length], MSG_DONTWAIT
  483.         cmp     eax, 0xffffffff
  484.         je      .check_socket
  485.  
  486.         test    eax, eax
  487.         jz      .server_closed
  488.         DEBUGF  1, "Received %u bytes\n", eax
  489.  
  490. ; Update timestamp
  491.         push    eax
  492.         mcall   29, 9
  493.         mov     [ebp + http_msg.timestamp], eax
  494.         pop     eax
  495.  
  496. ; Update pointers
  497.         mov     edi, [ebp + http_msg.write_ptr]
  498.         add     [ebp + http_msg.write_ptr], eax
  499.         sub     [ebp + http_msg.buffer_length], eax
  500.         jz      .got_all_data
  501.  
  502. ; If data is chunked, combine chunks into contiguous data.
  503.         test    [ebp + http_msg.flags], FLAG_CHUNKED
  504.         jnz     .chunk_loop
  505.  
  506. ; Did we detect the (final) header yet?
  507.         test    [ebp + http_msg.flags], FLAG_GOT_HEADER
  508.         jnz     .header_parsed
  509.  
  510. ; We havent found the (final) header yet, search for it..
  511.   .scan_again:
  512.         ; eax = total number of bytes received so far
  513.         mov     eax, [ebp + http_msg.write_ptr]
  514.         sub     eax, http_msg.data
  515.         sub     eax, ebp
  516.         sub     eax, [ebp + http_msg.header_length]
  517.         ; edi is ptr to begin of header
  518.         lea     edi, [ebp + http_msg.data]
  519.         add     edi, [ebp + http_msg.header_length]
  520.         ; put it in esi for next proc too
  521.         mov     esi, edi
  522.         sub     eax, 3
  523.         jle     .need_more_data
  524.   .scan_loop:
  525.         ; scan for end of header (empty line)
  526.         cmp     dword[edi], 0x0a0d0a0d                  ; end of header
  527.         je      .end_of_header
  528.         cmp     word[edi+2], 0x0a0a                     ; notice the use of offset + 2, to calculate header length correctly :)
  529.         je      .end_of_header
  530.         inc     edi
  531.         dec     eax
  532.         jnz     .scan_loop
  533.         jmp     .need_more_data
  534.  
  535.   .end_of_header:
  536.         add     edi, 4 - http_msg.data
  537.         sub     edi, ebp
  538.         mov     [ebp + http_msg.header_length], edi     ; If this isnt the final header, we'll use this as an offset to find real header.
  539.         DEBUGF  1, "Header length: %u\n", edi
  540.  
  541. ; Ok, we have found header:
  542.         cmp     dword[esi], 'HTTP'
  543.         jne     .invalid_header
  544.         cmp     dword[esi+4], '/1.0'
  545.         je      .http_1.0
  546.         cmp     dword[esi+4], '/1.1'
  547.         jne     .invalid_header
  548.         or      [ebp + http_msg.flags], FLAG_HTTP11
  549.   .http_1.0:
  550.         cmp     byte[esi+8], ' '
  551.         jne     .invalid_header
  552.  
  553.         add     esi, 9
  554.         xor     eax, eax
  555.         xor     ebx, ebx
  556.         mov     ecx, 3
  557.   .statusloop:
  558.         lodsb
  559.         sub     al, '0'
  560.         jb      .invalid_header
  561.         cmp     al, 9
  562.         ja      .invalid_header
  563.         lea     ebx, [ebx + 4*ebx]
  564.         shl     ebx, 1
  565.         add     ebx, eax
  566.         dec     ecx
  567.         jnz     .statusloop
  568.  
  569. ; Ignore "100 - Continue" headers
  570.         cmp     ebx, 100
  571.         je      .scan_again
  572.  
  573.         DEBUGF  1, "Status: %u\n", ebx
  574.         mov     [ebp + http_msg.status], ebx
  575.         or      [ebp + http_msg.flags], FLAG_GOT_HEADER
  576.  
  577. ; Now, convert all header names to lowercase.
  578. ; This way, it will be much easier to find certain header fields, later on.
  579.  
  580.         lea     esi, [ebp + http_msg.data]
  581.         mov     ecx, [ebp + http_msg.header_length]
  582.   .need_newline:
  583.         inc     esi
  584.         dec     ecx
  585.         jz      .convert_done
  586.         cmp     byte[esi], 10
  587.         jne     .need_newline
  588. ; Ok, we have a newline, a line beginning with space or tabs has no header fields.
  589.  
  590.         inc     esi
  591.         dec     ecx
  592.         jz      .convert_done
  593.         cmp     byte[esi], ' '
  594.         je      .need_newline
  595.         cmp     byte[esi], 9    ; horizontal tab
  596.         je      .need_newline
  597.         jmp     .convert_loop
  598.   .next_char:
  599.         inc     esi
  600.         dec     ecx
  601.         jz      .convert_done
  602.   .convert_loop:
  603.         cmp     byte[esi], ':'
  604.         je      .need_newline
  605.         cmp     byte[esi], 'A'
  606.         jb      .next_char
  607.         cmp     byte[esi], 'Z'
  608.         ja      .next_char
  609.         or      byte[esi], 0x20 ; convert to lowercase
  610.         jmp     .next_char
  611.   .convert_done:
  612.         mov     byte[esi-1], 0
  613.         lea     esi, [ebp + http_msg.data]
  614.         DEBUGF  1, "Header names converted to lowercase:\n%s\n", esi
  615.  
  616. ; Check for content-length header field.
  617.         stdcall HTTP_find_header_field, ebp, str_cl
  618.         test    eax, eax
  619.         jz      .no_content
  620.         or      [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  621.  
  622.         xor     edx, edx
  623.   .cl_loop:
  624.         movzx   ebx, byte[eax]
  625.         inc     eax
  626.         cmp     bl, 10
  627.         je      .cl_ok
  628.         cmp     bl, 13
  629.         je      .cl_ok
  630.         cmp     bl, ' '
  631.         je      .cl_ok
  632.         sub     bl, '0'
  633.         jb      .invalid_header
  634.         cmp     bl, 9
  635.         ja      .invalid_header
  636.         lea     edx, [edx + edx*4]      ; edx = edx*10
  637.         shl     edx, 1                  ;
  638.         add     edx, ebx
  639.         jmp     .cl_loop
  640.  
  641.   .cl_ok:
  642.         mov     [ebp + http_msg.content_length], edx
  643.         DEBUGF  1, "Content-length: %u\n", edx
  644.  
  645. ; Resize buffer according to content-length.
  646.         add     edx, [ebp + http_msg.header_length]
  647.         add     edx, http_msg.data
  648.  
  649.         mov     ecx, edx
  650.         sub     ecx, [ebp + http_msg.write_ptr]
  651.         mov     [ebp + http_msg.buffer_length], ecx
  652.  
  653.         invoke  mem.realloc, ebp, edx
  654.         or      eax, eax
  655.         jz      .no_ram
  656.  
  657.   .not_chunked:
  658.         mov     eax, [ebp + http_msg.write_ptr]
  659.         sub     eax, [ebp + http_msg.header_length]
  660.         sub     eax, http_msg.data
  661.         sub     eax, ebp
  662.         jmp     .header_parsed  ; hooray!
  663.  
  664.   .no_content:
  665.         DEBUGF  1, "Content-length not found.\n"
  666.  
  667. ; We didnt find 'content-length', maybe server is using chunked transfer encoding?
  668. ; Try to find 'transfer-encoding' header.
  669.         stdcall HTTP_find_header_field, ebp, str_te
  670.         test    eax, eax
  671.         jz      .not_chunked
  672.  
  673.         mov     ebx, dword[eax]
  674.         or      ebx, 0x20202020
  675.         cmp     ebx, 'chun'
  676.         jne     .not_chunked
  677.         mov     ebx, dword[eax+4]
  678.         or      ebx, 0x00202020
  679.         and     ebx, 0x00ffffff
  680.         cmp     ebx, 'ked'
  681.         jne     .not_chunked
  682.  
  683.         or      [ebp + http_msg.flags], FLAG_CHUNKED
  684.         DEBUGF  1, "Transfer type is: chunked\n"
  685.  
  686. ; Set chunk pointer where first chunk should begin.
  687.         lea     eax, [ebp + http_msg.data]
  688.         add     eax, [ebp + http_msg.header_length]
  689.         mov     [ebp + http_msg.chunk_ptr], eax
  690.  
  691.   .chunk_loop:
  692.         mov     ecx, [ebp + http_msg.write_ptr]
  693.         sub     ecx, [ebp + http_msg.chunk_ptr]
  694.         jb      .need_more_data_chunked         ; TODO: use this ecx !!!
  695.  
  696. ; Chunkline starts here, convert the ASCII hex number into ebx
  697.         mov     esi, [ebp + http_msg.chunk_ptr]
  698.         xor     ebx, ebx
  699.   .chunk_hexloop:
  700.         lodsb
  701.         sub     al, '0'
  702.         jb      .chunk_
  703.         cmp     al, 9
  704.         jbe     .chunk_hex
  705.         sub     al, 'A' - '0' - 10
  706.         jb      .chunk_
  707.         cmp     al, 15
  708.         jbe     .chunk_hex
  709.         sub     al, 'a' - 'A'
  710.         cmp     al, 15
  711.         ja      .chunk_
  712.   .chunk_hex:
  713.         shl     ebx, 4
  714.         add     bl, al
  715.         jmp     .chunk_hexloop
  716.   .chunk_:
  717.         DEBUGF  1, "got chunk of %u bytes\n", ebx
  718. ;;        cmp     esi, [ebp + http_msg.chunk_ptr]
  719. ;;        je
  720. ; If chunk size is 0, all chunks have been received.
  721.         test    ebx, ebx
  722.         jz      .got_all_data_chunked           ; last chunk, hooray! FIXME: what if it wasnt a valid hex number???
  723.  
  724. ; Chunkline ends with a CR, LF or simply LF
  725.   .end_of_chunkline?:
  726.         cmp     al, 10
  727.         je      .end_of_chunkline
  728.         lodsb
  729.         cmp     edi, [ebp + http_msg.write_ptr]
  730.         jb      .end_of_chunkline?
  731.         jmp     .need_more_data
  732.  
  733.   .end_of_chunkline:
  734. ; Update chunk ptr, and remember old one
  735.         mov     edi, [ebp + http_msg.chunk_ptr]
  736.         add     [ebp + http_msg.chunk_ptr], ebx
  737. ; Realloc buffer, make it 'chunksize' bigger.
  738.         mov     eax, [ebp + http_msg.buffer_length]
  739.         add     eax, ebx
  740.         invoke  mem.realloc, ebp, eax
  741.         or      eax, eax
  742.         jz      .no_ram
  743.         add     [ebp + http_msg.buffer_length], ebx
  744.  
  745. ; Update write ptr
  746.         mov     eax, esi
  747.         sub     eax, edi
  748.         sub     [ebp + http_msg.write_ptr], eax
  749.  
  750. ; Now move all received data to the left (remove chunk header).
  751. ; Update content_length accordingly.
  752.         mov     ecx, [ebp + http_msg.write_ptr]
  753.         sub     ecx, esi
  754.         add     [ebp + http_msg.content_received], ecx
  755.         rep     movsb
  756.         jmp     .chunk_loop
  757.  
  758. ; Check if we got all the data.
  759.   .header_parsed:
  760.         add     [ebp + http_msg.content_received], eax
  761.         test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  762.         jz      .need_more_data_and_space
  763.         mov     eax, [ebp + http_msg.content_received]
  764.         cmp     eax, [ebp + http_msg.content_length]
  765.         jae     .got_all_data
  766.         jmp     .need_more_data
  767.  
  768.   .need_more_data_and_space:
  769.         mov     eax, [ebp + http_msg.write_ptr]
  770.         add     eax, BUFFERSIZE
  771.         sub     eax, ebp
  772.         invoke  mem.realloc, ebp, eax
  773.         or      eax, eax
  774.         jz      .no_ram
  775.         mov     [ebp + http_msg.buffer_length], BUFFERSIZE
  776.  
  777.   .need_more_data:
  778.         popa
  779.         xor     eax, eax
  780.         dec     eax
  781.         ret
  782.  
  783.   .need_more_data_chunked:
  784.         add     [ebp + http_msg.content_received], eax
  785.         popa
  786.         xor     eax, eax
  787.         dec     eax
  788.         ret
  789.  
  790.   .got_all_data_chunked:
  791.         mov     eax, [ebp + http_msg.chunk_ptr]
  792.         sub     eax, [ebp + http_msg.header_length]
  793.         sub     eax, http_msg.data
  794.         sub     eax, ebp
  795.         mov     [ebp + http_msg.content_length], eax
  796.         mov     [ebp + http_msg.content_received], eax
  797.   .got_all_data:
  798.         DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_received]
  799.         or      [ebp + http_msg.flags], FLAG_GOT_ALL_DATA
  800.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  801.         mcall   close, [ebp + http_msg.socket]
  802.         popa
  803.         xor     eax, eax
  804.         ret
  805.  
  806.   .check_socket:
  807.         cmp     ebx, EWOULDBLOCK
  808.         jne     .socket_error
  809.  
  810.         mcall   29, 9
  811.         sub     eax, TIMEOUT
  812.         cmp     eax, [ebp + http_msg.timestamp]
  813.         jb      .need_more_data
  814.         DEBUGF  1, "ERROR: timeout\n"
  815.         or      [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR
  816.         jmp     .disconnect
  817.  
  818.   .server_closed:
  819.         DEBUGF  1, "server closed connection, transfer complete?\n"
  820.         test    [ebp + http_msg.flags], FLAG_GOT_HEADER
  821.         jz      .server_error
  822.         test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  823.         jz      .got_all_data
  824.  
  825.   .server_error:
  826.         pop     eax
  827.         DEBUGF  1, "ERROR: server closed connection unexpectedly\n"
  828.         or      [ebp + http_msg.flags], FLAG_TRANSFER_FAILED
  829.         jmp     .disconnect
  830.  
  831.   .invalid_header:
  832.         pop     eax
  833.         DEBUGF  1, "ERROR: invalid header\n"
  834.         or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
  835.         jmp     .disconnect
  836.  
  837.   .no_ram:
  838.         DEBUGF  1, "ERROR: out of RAM\n"
  839.         or      [ebp + http_msg.flags], FLAG_NO_RAM
  840.         jmp     .disconnect
  841.  
  842.   .socket_error:
  843.         DEBUGF  1, "ERROR: socket error %u\n", ebx
  844.         or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
  845.   .disconnect:
  846.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  847.         mcall   close, [ebp + http_msg.socket]
  848.   .connection_closed:
  849.         popa
  850.         xor     eax, eax
  851.         ret
  852.  
  853. endp
  854.  
  855.  
  856.  
  857.  
  858. ;;================================================================================================;;
  859. proc HTTP_free identifier ;///////////////////////////////////////////////////////////////////////;;
  860. ;;------------------------------------------------------------------------------------------------;;
  861. ;? Free the http_msg structure                                                                    ;;
  862. ;;------------------------------------------------------------------------------------------------;;
  863. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  864. ;;------------------------------------------------------------------------------------------------;;
  865. ;< none                                                                                           ;;
  866. ;;================================================================================================;;
  867.  
  868.         pusha
  869.         mov     ebp, [identifier]
  870.  
  871.         test    [ebp + http_msg.flags], FLAG_CONNECTED
  872.         jz      .not_connected
  873.  
  874.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  875.         mcall   close, [ebp + http_msg.socket]
  876.  
  877.   .not_connected:
  878.         invoke  mem.free, ebp
  879.  
  880.         popa
  881.         ret
  882.  
  883. endp
  884.  
  885.  
  886.  
  887. ;;================================================================================================;;
  888. proc HTTP_stop identifier ;///////////////////////////////////////////////////////////////////////;;
  889. ;;------------------------------------------------------------------------------------------------;;
  890. ;? Stops the open connection                                                                      ;;
  891. ;;------------------------------------------------------------------------------------------------;;
  892. ;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
  893. ;;------------------------------------------------------------------------------------------------;;
  894. ;< none                                                                                           ;;
  895. ;;================================================================================================;;
  896.  
  897.         pusha
  898.         mov     ebp, [identifier]
  899.  
  900.         and     [ebp + http_msg.flags], not FLAG_CONNECTED
  901.         mcall   close, [ebp + http_msg.socket]
  902.  
  903.         popa
  904.         ret
  905.  
  906. endp
  907.  
  908.  
  909.  
  910. ;;================================================================================================;;
  911. proc HTTP_find_header_field identifier, headername ;//////////////////////////////////////////////;;
  912. ;;------------------------------------------------------------------------------------------------;;
  913. ;? Find a header field in the received HTTP header                                                ;;
  914. ;;------------------------------------------------------------------------------------------------;;
  915. ;> identifier   = ptr to http_msg struct                                                          ;;
  916. ;> headername   = ptr to ASCIIZ string containg field you want to find (must be in lowercase)     ;;
  917. ;;------------------------------------------------------------------------------------------------;;
  918. ;< eax = 0 (error) / ptr to content of the HTTP header field                                      ;;
  919. ;;================================================================================================;;
  920.         push    ebx ecx edx esi edi
  921.  
  922.         DEBUGF  1, "Find header field: %s\n", [headername]
  923.  
  924.         mov     ebx, [identifier]
  925.         test    [ebx + http_msg.flags], FLAG_GOT_HEADER
  926.         jz      .fail
  927.  
  928.         lea     edx, [ebx + http_msg.data]
  929.         mov     ecx, edx
  930.         add     ecx, [ebx + http_msg.header_length]
  931.  
  932.   .restart:
  933.         mov     esi, [headername]
  934.         mov     edi, edx
  935.   .loop:
  936.         cmp     edi, ecx
  937.         jae     .fail
  938.         lodsb
  939.         scasb
  940.         je      .loop
  941.         test    al, al
  942.         jz      .done?
  943.   .next:
  944.         inc     edx
  945.         jmp     .restart
  946.  
  947.   .not_done:
  948.         inc     edi
  949.   .done?:
  950.         cmp     byte[edi-1], ':'
  951.         je      .almost_done
  952.         cmp     byte[edi-1], ' '
  953.         je      .not_done
  954.         cmp     byte[edi-1], 9  ; tab
  955.         je      .not_done
  956.  
  957.         jmp     .next
  958.  
  959.   .almost_done:                 ; FIXME: buffer overflow?
  960.         dec     edi
  961.         DEBUGF  1, "Found header field\n"
  962.   .spaceloop:
  963.         inc     edi
  964.         cmp     byte[edi], ' '
  965.         je      .spaceloop
  966.         cmp     byte[edi], 9    ; tab
  967.         je      .spaceloop
  968.  
  969.         mov     eax, edi
  970.         pop     edi esi edx ecx ebx
  971.         ret
  972.  
  973.   .fail:
  974.         pop     edi esi edx ecx ebx
  975.         xor     eax, eax
  976.         ret
  977.  
  978. endp
  979.  
  980.  
  981.  
  982. ;;================================================================================================;;
  983. proc URI_escape URI ;/////////////////////////////////////////////////////////////////////////////;;
  984. ;;------------------------------------------------------------------------------------------------;;
  985. ;?                                                                                                ;;
  986. ;;------------------------------------------------------------------------------------------------;;
  987. ;> URI = ptr to ASCIIZ URI                                                                        ;;
  988. ;;------------------------------------------------------------------------------------------------;;
  989. ;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
  990. ;;================================================================================================;;
  991.  
  992.         pusha
  993.  
  994.         invoke  mem.alloc, URLMAXLEN
  995.         test    eax, eax
  996.         jz      .error
  997.         mov     [esp + 7 * 4], eax              ; return ptr in eax
  998.         mov     esi, [URI]
  999.         mov     edi, eax
  1000.         xor     ebx, ebx
  1001.         xor     ecx, ecx
  1002.   .loop:
  1003.         lodsb
  1004.         test    al, al
  1005.         jz      .done
  1006.  
  1007.         mov     cl, al
  1008.         and     cl, 0x1f
  1009.         mov     bl, al
  1010.         shr     bl, 5
  1011.         bt      dword[bits_must_escape + ebx], ecx
  1012.         jc      .escape
  1013.  
  1014.         stosb
  1015.         jmp     .loop
  1016.  
  1017.   .escape:
  1018.         mov     al, '%'
  1019.         stosb
  1020.         mov     bl, byte[esi-1]
  1021.         shr     bl, 4
  1022.         mov     al, byte[str_hex + ebx]
  1023.         stosb
  1024.         mov     bl, byte[esi-1]
  1025.         and     bl, 0x0f
  1026.         mov     al, byte[str_hex + ebx]
  1027.         stosb
  1028.         jmp     .loop
  1029.  
  1030.  
  1031.   .done:
  1032.         stosb
  1033.  
  1034.         popa
  1035.         ret
  1036.  
  1037.   .error:
  1038.         popa
  1039.         xor     eax, eax
  1040.         ret
  1041.  
  1042. endp
  1043.  
  1044.  
  1045.  
  1046. ;;================================================================================================;;
  1047. proc URI_unescape URI ;///////////////////////////////////////////////////////////////////////////;;
  1048. ;;------------------------------------------------------------------------------------------------;;
  1049. ;?                                                                                                ;;
  1050. ;;------------------------------------------------------------------------------------------------;;
  1051. ;> URI = ptr to ASCIIZ URI                                                                        ;;
  1052. ;;------------------------------------------------------------------------------------------------;;
  1053. ;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
  1054. ;;================================================================================================;;
  1055.  
  1056.         pusha
  1057.  
  1058.         invoke  mem.alloc, URLMAXLEN
  1059.         test    eax, eax
  1060.         jz      .error
  1061.         mov     [esp + 7 * 4], eax              ; return ptr in eax
  1062.         mov     esi, [URI]
  1063.         mov     edi, eax
  1064.   .loop:
  1065.         lodsb
  1066.         test    al, al
  1067.         jz      .done
  1068.  
  1069.         cmp     al, '%'
  1070.         je      .unescape
  1071.  
  1072.         stosb
  1073.         jmp     .loop
  1074.  
  1075.   .unescape:
  1076.         xor     ebx, ebx
  1077.         xor     ecx, ecx
  1078.   .unescape_nibble:
  1079.         lodsb
  1080.         sub     al, '0'
  1081.         jb      .fail
  1082.         cmp     al, 9
  1083.         jbe     .nibble_ok
  1084.         sub     al, 'A' - '0' - 10
  1085.         jb      .fail
  1086.         cmp     al, 15
  1087.         jbe     .nibble_ok
  1088.         sub     al, 'a' - 'A'
  1089.         cmp     al, 15
  1090.         ja      .fail
  1091.   .nibble_ok:
  1092.         shl     bl, 8
  1093.         or      bl, al
  1094.         dec     ecx
  1095.         jc      .unescape_nibble
  1096.         mov     al, bl
  1097.         stosb
  1098.         jmp     .loop
  1099.  
  1100.   .fail:
  1101.         DEBUGF  1, "ERROR: invalid URI!\n"
  1102.         jmp     .loop
  1103.  
  1104.   .done:
  1105.         stosb
  1106.  
  1107.         popa
  1108.         ret
  1109.  
  1110.   .error:
  1111.         popa
  1112.         xor     eax, eax
  1113.         ret
  1114.  
  1115. endp
  1116.  
  1117.  
  1118.  
  1119.  
  1120.  
  1121. ;;================================================================================================;;
  1122. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1123. ;;================================================================================================;;
  1124. ;! Internal procedures section                                                                    ;;
  1125. ;;                                                                                                ;;
  1126. ;; NOTICE: These procedures do not follow stdcall conventions and thus may destroy any register.  ;;
  1127. ;;================================================================================================;;
  1128. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1129. ;;================================================================================================;;
  1130.  
  1131.  
  1132.  
  1133.  
  1134. ;;================================================================================================;;
  1135. proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
  1136. ;;------------------------------------------------------------------------------------------------;;
  1137. ;? Connects to a HTTP server                                                                      ;;
  1138. ;;------------------------------------------------------------------------------------------------;;
  1139. ;> hostname     = ptr to ASCIIZ hostname                                                          ;;
  1140. ;> port         = port (x86 byte order)                                                           ;;
  1141. ;;------------------------------------------------------------------------------------------------;;
  1142. ;< eax = 0 (error) / socketnum                                                                    ;;
  1143. ;;================================================================================================;;
  1144.  
  1145. locals
  1146.         sockaddr        dd ?
  1147.         socketnum       dd ?
  1148. endl
  1149.  
  1150. ; Resolve the hostname
  1151.         DEBUGF  1, "Resolving hostname\n"
  1152.         push    esp     ; reserve stack place
  1153.         push    esp     ; fourth parameter
  1154.         push    0       ; third parameter
  1155.         push    0       ; second parameter
  1156.         push    [hostname]
  1157.         call    [getaddrinfo]
  1158.         pop     esi
  1159.         test    eax, eax
  1160.         jnz     .error1
  1161.  
  1162. ; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
  1163.         mov     esi, [esi + addrinfo.ai_addr]
  1164.         mov     [sockaddr], esi
  1165.         mov     eax, [esi + sockaddr_in.sin_addr]
  1166.         test    eax, eax
  1167.         jz      .error2
  1168.  
  1169.         DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
  1170.         [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
  1171.         [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
  1172.  
  1173.         mov     [esi + sockaddr_in.sin_family], AF_INET4
  1174.         mov     eax, [port]
  1175.         xchg    al, ah
  1176.         mov     [esi + sockaddr_in.sin_port], ax
  1177.  
  1178. ; Connect to the server.
  1179.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  1180.         test    eax, eax
  1181.         jz      .error2
  1182.         mov     [socketnum], eax
  1183.         DEBUGF  1, "Socket: 0x%x\n", eax
  1184.  
  1185.         mcall   connect, [socketnum], [sockaddr], 18
  1186.         test    eax, eax
  1187.         jnz     .error2
  1188.         DEBUGF  1, "Socket is now connected.\n"
  1189.  
  1190. ; free allocated memory
  1191.         push    [sockaddr]
  1192.         call    [freeaddrinfo]
  1193.  
  1194.         mov     eax, [socketnum]
  1195.         ret
  1196.  
  1197.   .error2:
  1198.  
  1199. ; free allocated memory
  1200.         push    [sockaddr]
  1201.         call    [freeaddrinfo]
  1202.  
  1203.   .error1:
  1204.         xor     eax, eax
  1205.         ret
  1206.  
  1207. endp
  1208.  
  1209.  
  1210. ;;================================================================================================;;
  1211. proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
  1212. ;;------------------------------------------------------------------------------------------------;;
  1213. ;? Split a given URL into hostname and pageaddr                                                   ;;
  1214. ;;------------------------------------------------------------------------------------------------;;
  1215. ;> URL = ptr to ASCIIZ URL                                                                        ;;
  1216. ;;------------------------------------------------------------------------------------------------;;
  1217. ;< eax = 0 (error) / ptr to ASCIIZ hostname                                                       ;;
  1218. ;< ebx = ptr to ASCIIZ pageaddr                                                                   ;;
  1219. ;;================================================================================================;;
  1220.  
  1221. locals
  1222.         urlsize         dd ?
  1223.         hostname        dd ?
  1224.         pageaddr        dd ?
  1225. endl
  1226.  
  1227.         DEBUGF  1, "parsing URL: %s\n", [URL]
  1228.  
  1229. ; remove any leading protocol text
  1230.         mov     esi, [URL]
  1231.         mov     ecx, URLMAXLEN
  1232.         mov     ax, '//'
  1233.   .loop1:
  1234.         cmp     byte[esi], 0            ; end of URL?
  1235.         je      .url_ok                 ; yep, so not found
  1236.         cmp     [esi], ax
  1237.         je      .skip_proto
  1238.         inc     esi
  1239.         dec     ecx
  1240.         jnz     .loop1
  1241.  
  1242.         DEBUGF  1, "Invalid URL\n"
  1243.         xor     eax, eax
  1244.         ret
  1245.  
  1246.   .skip_proto:
  1247.         inc     esi                     ; skip the two '/'
  1248.         inc     esi
  1249.         mov     [URL], esi              ; update pointer so it skips protocol
  1250.         jmp     .loop1                  ; we still need to find the length of the URL
  1251.  
  1252.   .url_ok:
  1253.         sub     esi, [URL]              ; calculate total length of URL
  1254.         mov     [urlsize], esi
  1255.  
  1256.  
  1257. ; now look for page delimiter - it's a '/' character
  1258.         mov     ecx, esi                ; URL length
  1259.         mov     edi, [URL]
  1260.         mov     al, '/'
  1261.         repne   scasb
  1262.         jne     @f
  1263.         dec     edi                     ; return one char, '/' must be part of the pageaddr
  1264.         inc     ecx                     ;
  1265.   @@:
  1266.         push    ecx edi                 ; remember the pointer and length of pageaddr
  1267.  
  1268.  
  1269. ; Create new buffer and put hostname in it
  1270.         mov     ecx, edi
  1271.         sub     ecx, [URL]
  1272.         inc     ecx                     ; we will add a 0 byte at the end
  1273.         invoke  mem.alloc, ecx
  1274.         or      eax, eax
  1275.         jz      .no_mem
  1276.  
  1277.         mov     [hostname], eax         ; copy hostname to buffer
  1278.         mov     edi, eax
  1279.         mov     esi, [URL]
  1280.         dec     ecx
  1281.         rep     movsb
  1282.         xor     al, al
  1283.         stosb
  1284.  
  1285.         mov     [pageaddr], str_slash   ; assume there is no pageaddr
  1286.         pop     esi ecx
  1287.         test    ecx, ecx
  1288.         jz      .no_page
  1289.         inc     ecx                     ; we will add a 0 byte at the end
  1290.         invoke  mem.alloc, ecx
  1291.         or      eax, eax
  1292.         jz      .no_mem
  1293.  
  1294.         mov     [pageaddr], eax         ; copy pageaddr to buffer
  1295.         mov     edi, eax
  1296.         dec     ecx
  1297.         rep     movsb
  1298.         xor     al, al
  1299.         stosb
  1300.   .no_page:
  1301.  
  1302.         mov     eax, [hostname]
  1303.         mov     ebx, [pageaddr]
  1304.         mov     ecx, 80                 ;;;; FIXME
  1305.  
  1306.         DEBUGF  1, "hostname: %s\n", eax
  1307.         DEBUGF  1, "pageaddr: %s\n", ebx
  1308.         DEBUGF  1, "port: %u\n", ecx
  1309.  
  1310.         ret
  1311.  
  1312.   .no_mem:
  1313.         xor     eax, eax
  1314.         ret
  1315.  
  1316. endp
  1317.  
  1318.  
  1319. ;;================================================================================================;;
  1320. proc ascii_dec ;//////////////////////////////////////////////////////////////////////////////////;;
  1321. ;;------------------------------------------------------------------------------------------------;;
  1322. ;? Convert eax to ASCII decimal number                                                            ;;
  1323. ;;------------------------------------------------------------------------------------------------;;
  1324. ;> eax = number                                                                                   ;;
  1325. ;> edi = ptr where to write ASCII decimal number                                                  ;;
  1326. ;;------------------------------------------------------------------------------------------------;;
  1327. ;< /                                                                                              ;;
  1328. ;;================================================================================================;;
  1329.  
  1330.         push    -'0'
  1331.         mov     ecx, 10
  1332.   .loop:
  1333.         xor     edx, edx
  1334.         div     ecx
  1335.         add     dl, '0'
  1336.         push    edx
  1337.         test    eax, eax
  1338.         jnz     .loop
  1339.  
  1340.   .loop2:
  1341.         pop     eax
  1342.         add     al, '0'
  1343.         jz      .done
  1344.         stosb
  1345.         jmp     .loop2
  1346.   .done:
  1347.  
  1348.         ret
  1349.  
  1350. endp
  1351.  
  1352.  
  1353. ;;================================================================================================;;
  1354. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1355. ;;================================================================================================;;
  1356. ;! Imported functions section                                                                     ;;
  1357. ;;================================================================================================;;
  1358. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  1359. ;;================================================================================================;;
  1360.  
  1361.  
  1362. align 16
  1363. @IMPORT:
  1364.  
  1365. library \
  1366.         libini, 'libini.obj', \
  1367.         network, 'network.obj'
  1368.  
  1369. import  libini, \
  1370.         ini.get_str, 'ini_get_str', \
  1371.         ini.get_int, 'ini_get_int'
  1372.  
  1373. import  network,\
  1374.         getaddrinfo, 'getaddrinfo',\
  1375.         freeaddrinfo,  'freeaddrinfo',\
  1376.         inet_ntoa, 'inet_ntoa'
  1377.  
  1378. ;;===========================================================================;;
  1379. ;;///////////////////////////////////////////////////////////////////////////;;
  1380. ;;===========================================================================;;
  1381. ;! Exported functions section                                                ;;
  1382. ;;===========================================================================;;
  1383. ;;///////////////////////////////////////////////////////////////////////////;;
  1384. ;;===========================================================================;;
  1385.  
  1386.  
  1387. align 4
  1388. @EXPORT:
  1389. export  \
  1390.         lib_init                , 'lib_init'            , \
  1391.         0x00010001              , 'version'             , \
  1392.         HTTP_get                , 'get'                 , \
  1393.         HTTP_head               , 'head'                , \
  1394.         HTTP_post               , 'post'                , \
  1395.         HTTP_find_header_field  , 'find_header_field'   , \
  1396.         HTTP_process            , 'process'             , \
  1397.         HTTP_free               , 'free'                , \
  1398.         HTTP_stop               , 'stop'                , \
  1399.         URI_escape              , 'escape'              , \
  1400.         URI_unescape            , 'unescape'
  1401.  
  1402. ;        HTTP_put                , 'put'                 , \
  1403. ;        HTTP_delete             , 'delete'              , \
  1404. ;        HTTP_trace              , 'trace'               , \
  1405. ;        HTTP_connect            , 'connect'             , \
  1406.  
  1407.  
  1408.  
  1409. section '.data' data readable writable align 16
  1410.  
  1411. inifile         db '/sys/settings/network.ini', 0
  1412.  
  1413. sec_proxy:
  1414. key_proxy       db 'proxy', 0
  1415. key_proxyport   db 'port', 0
  1416. key_user        db 'user', 0
  1417. key_password    db 'password', 0
  1418.  
  1419. str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
  1420.   .length       = $ - str_http11
  1421. str_post_cl     db 13, 10, 'Content-Length: '
  1422.   .length       = $ - str_post_cl
  1423. str_post_ct     db 13, 10, 'Content-Type: '
  1424.   .length       = $ - str_post_ct
  1425. str_close       db 13, 10, 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
  1426.   .length       = $ - str_close
  1427. str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
  1428.   .length       = $ - str_proxy_auth
  1429.  
  1430. base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  1431.                 db '0123456789+/'
  1432.  
  1433. str_cl          db 'content-length', 0
  1434. str_slash       db '/', 0
  1435. str_te          db 'transfer-encoding', 0
  1436. str_get         db 'GET ', 0
  1437. str_head        db 'HEAD ', 0
  1438. str_post        db 'POST ', 0
  1439.  
  1440. bits_must_escape:
  1441. dd      0xffffffff                                                      ; 00-1F
  1442. dd      1 shl 0 + 1 shl 2 + 1 shl 3 + 1 shl 5 + 1 shl 28 + 1 shl 30     ; "#%<>
  1443. dd      1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 30                       ;[\]^
  1444. dd      1 shl 0 + 1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 31             ;`{|} DEL
  1445.  
  1446. dd      0xffffffff
  1447. dd      0xffffffff
  1448. dd      0xffffffff
  1449. dd      0xffffffff
  1450.  
  1451. str_hex:
  1452. db '0123456789ABCDEF'
  1453.  
  1454. include_debug_strings
  1455.  
  1456. ; uninitialized data
  1457. mem.alloc       dd ?
  1458. mem.free        dd ?
  1459. mem.realloc     dd ?
  1460. dll.load        dd ?
  1461.  
  1462. proxyAddr       rb 256
  1463. proxyUser       rb 256
  1464. proxyPassword   rb 256
  1465. proxyPort       dd ?