Subversion Repositories Kolibri OS

Rev

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