Subversion Repositories Kolibri OS

Rev

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