Subversion Repositories Kolibri OS

Rev

Rev 4161 | Rev 4167 | 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.  
  23.         __DEBUG__       = 1
  24.         __DEBUG_LEVEL__ = 1
  25.  
  26.  
  27. format MS COFF
  28.  
  29. public @EXPORT as 'EXPORTS'
  30.  
  31. include '../../../struct.inc'
  32. include '../../../proc32.inc'
  33. include '../../../macros.inc'
  34. purge section,mov,add,sub
  35. include '../../../debug-fdo.inc'
  36.  
  37. include '../../../network.inc'
  38. include 'http.inc'
  39.  
  40. virtual at 0
  41.         http_msg http_msg
  42. end virtual
  43.  
  44. macro copy_till_zero {
  45.   @@:
  46.         lodsb
  47.         test    al, al
  48.         jz      @f
  49.         stosb
  50.         jmp     @r
  51.   @@:
  52. }
  53.  
  54. section '.flat' code readable align 16
  55.  
  56. ;;===========================================================================;;
  57. lib_init: ;//////////////////////////////////////////////////////////////////;;
  58. ;;---------------------------------------------------------------------------;;
  59. ;? Library entry point (called after library load)                           ;;
  60. ;;---------------------------------------------------------------------------;;
  61. ;> eax = pointer to memory allocation routine                                ;;
  62. ;> ebx = pointer to memory freeing routine                                   ;;
  63. ;> ecx = pointer to memory reallocation routine                              ;;
  64. ;> edx = pointer to library loading routine                                  ;;
  65. ;;---------------------------------------------------------------------------;;
  66. ;< eax = 1 (fail) / 0 (ok) (library initialization result)                   ;;
  67. ;;===========================================================================;;
  68.         mov     [mem.alloc], eax
  69.         mov     [mem.free], ebx
  70.         mov     [mem.realloc], ecx
  71.         mov     [dll.load], edx
  72.  
  73.         invoke  dll.load, @IMPORT
  74.         or      eax, eax
  75.         jz      .ok
  76.  
  77. ; load proxy settings
  78.         invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
  79.         invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
  80.         mov     [proxyPort], eax
  81.         invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
  82.         invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
  83.  
  84.         xor     eax, eax
  85.         inc     eax
  86.         ret
  87.  
  88.   .ok:
  89.         xor     eax, eax
  90.         ret
  91.  
  92.  
  93.  
  94.  
  95.  
  96. ;;================================================================================================;;
  97. proc HTTP_get URL ;///////////////////////////////////////////////////////////////////////////////;;
  98. ;;------------------------------------------------------------------------------------------------;;
  99. ;?                                                                                                ;;
  100. ;;------------------------------------------------------------------------------------------------;;
  101. ;> _                                                                                              ;;
  102. ;;------------------------------------------------------------------------------------------------;;
  103. ;< eax = 0 (error) / buffer ptr                                                                   ;;
  104. ;;================================================================================================;;
  105. locals
  106.         hostname        dd ?
  107.         pageaddr        dd ?
  108.         sockaddr        dd ?
  109.         socketnum       dd ?
  110.         buffer          dd ?
  111. endl
  112.  
  113. ; split the URL into hostname and pageaddr
  114.         stdcall parse_url, [URL]
  115.         test    eax, eax
  116.         jz      .error
  117.         mov     [hostname], eax
  118.         mov     [pageaddr], ebx
  119.  
  120. ; Do we need to use a proxy?
  121.         cmp     [proxyAddr], 0
  122.         jne     .proxy_done
  123.  
  124.         ; TODO
  125.   .proxy_done:
  126.  
  127. ; Resolve the hostname
  128.         DEBUGF  1, "Resolving hostname\n"
  129.         push    esp     ; reserve stack place
  130.         push    esp     ; fourth parameter
  131.         push    0       ; third parameter
  132.         push    0       ; second parameter
  133.         push    [hostname]
  134.         call    [getaddrinfo]
  135.         pop     esi
  136.         test    eax, eax
  137.         jnz     .error
  138.  
  139. ; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
  140.         mov     esi, [esi + addrinfo.ai_addr]
  141.         mov     [sockaddr], esi
  142.         mov     eax, [esi + sockaddr_in.sin_addr]
  143.         test    eax, eax
  144.         jz      .error
  145.  
  146.         DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
  147.         [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
  148.         [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
  149.  
  150.         mov     [esi + sockaddr_in.sin_family], AF_INET4
  151.         mov     [esi + sockaddr_in.sin_port], 80 shl 8  ;;; FIXME
  152.  
  153. ; Connect to the server.
  154.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  155.         test    eax, eax
  156.         jz      .error
  157.         mov     [socketnum], eax
  158.         DEBUGF  1, "Socket: 0x%x\n", eax
  159.  
  160.         mcall   connect, [socketnum], [sockaddr], 18
  161.         test    eax, eax
  162.         jnz     .error
  163.         DEBUGF  1, "Socket is now connected.\n"
  164.  
  165.         ; TODO: free address buffer(s)
  166.  
  167. ; Create the HTTP request.
  168.         invoke  mem.alloc, BUFFERSIZE
  169.         test    eax, eax
  170.         jz      .error
  171.         mov     [buffer], eax
  172.         DEBUGF  1, "Buffer has been allocated.\n"
  173.  
  174.         mov     dword[eax], 'GET '
  175.         lea     edi, [eax + 4]
  176.         mov     esi, [pageaddr] ; TODO: for proxy use http:// and then full URL
  177.         copy_till_zero
  178.  
  179.         mov     esi, str_http11
  180.         mov     ecx, str_http11.length
  181.         rep     movsb
  182.  
  183.         mov     esi, [hostname]
  184.         copy_till_zero
  185.  
  186.         mov     esi, str_close
  187.         mov     ecx, str_close.length
  188.         rep     movsb
  189.  
  190.         mov     byte[edi], 0
  191.         DEBUGF  1, "Request:\n%s", [buffer]
  192.  
  193. ; now send the request
  194.         mov     esi, edi
  195.         sub     esi, [buffer]   ; length
  196.         xor     edi, edi        ; flags
  197.  
  198.         mcall   send, [socketnum], [buffer]
  199.         test    eax, eax
  200.         jz      .error
  201.         DEBUGF  1, "Request has been sent to server.\n"
  202.  
  203. ; Now that we have sent the request, re-purpose buffer as receive buffer
  204.         mov     eax, [buffer]
  205.         push    [socketnum]
  206.         popd    [eax + http_msg.socket]
  207.         lea     esi, [eax + http_msg.data]
  208.         mov     [eax + http_msg.flags], 0
  209.         mov     [eax + http_msg.write_ptr], esi
  210.         mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.data
  211.         mov     [eax + http_msg.chunk_ptr], 0
  212.  
  213.         mov     [eax + http_msg.status], 0
  214.         mov     [eax + http_msg.header_length], 0
  215.         mov     [eax + http_msg.content_length], 0
  216.  
  217.         ret                     ; return buffer ptr
  218.  
  219.   .error:
  220.         DEBUGF  1, "Error!\n"
  221.         xor     eax, eax        ; return 0 = error
  222.         ret
  223.  
  224. endp
  225.  
  226.  
  227.  
  228. ;;================================================================================================;;
  229. proc HTTP_process identifier ;////////////////////////////////////////////////////////////////////;;
  230. ;;------------------------------------------------------------------------------------------------;;
  231. ;?                                                                                                ;;
  232. ;;------------------------------------------------------------------------------------------------;;
  233. ;> _                                                                                              ;;
  234. ;;------------------------------------------------------------------------------------------------;;
  235. ;< eax = -1 (not finished) / 0 finished                                                           ;;
  236. ;;================================================================================================;;
  237.         pusha
  238.         mov     ebp, [identifier]
  239.  
  240. ; Receive some data
  241.         mcall   recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
  242.                       [ebp + http_msg.buffer_length], MSG_DONTWAIT
  243.         cmp     eax, 0xffffffff
  244.         je      .check_socket
  245.         DEBUGF  1, "Received %u bytes\n", eax
  246.  
  247. ; Update pointers
  248.         mov     edi, [ebp + http_msg.write_ptr]
  249.         add     [ebp + http_msg.write_ptr], eax
  250.         sub     [ebp + http_msg.buffer_length], eax
  251.         jz      .got_all_data
  252.  
  253. ; If data is chunked, combine chunks into contiguous data.
  254.         test    [ebp + http_msg.flags], FLAG_CHUNKED
  255.         jnz     .chunk_loop
  256.  
  257. ; Did we detect the header yet?
  258.         test    [ebp + http_msg.flags], FLAG_GOT_HEADER
  259.         jnz     .header_parsed
  260.  
  261. ; We havent found the header yet, search for it..
  262.         sub     eax, 4
  263.         jl      .need_more_data
  264.   .scan:
  265.         ; scan for end of header (empty line)
  266.         cmp     dword[edi], 0x0a0d0a0d                  ; end of header
  267.         je      .end_of_header
  268.         cmp     word[edi+2], 0x0a0a
  269.         je      .end_of_header
  270.         inc     edi
  271.         dec     eax
  272.         jnz     .scan
  273.  
  274.   .end_of_header:
  275.         add     edi, 4 - http_msg.data
  276.         sub     edi, ebp
  277.         mov     [ebp + http_msg.header_length], edi
  278.         or      [ebp + http_msg.flags], FLAG_GOT_HEADER
  279.         DEBUGF  1, "Header length: %u\n", edi
  280.  
  281. ; Ok, we have found header:
  282.         cmp     dword[ebp + http_msg.data], 'HTTP'
  283.         jne     .invalid_header
  284.         cmp     dword[ebp + http_msg.data+4], '/1.0'
  285.         je      .http_1.0
  286.         cmp     dword[ebp + http_msg.data+4], '/1.1'
  287.         jne     .invalid_header
  288.         or      [ebp + http_msg.flags], FLAG_HTTP11
  289.   .http_1.0:
  290.         cmp     byte[ebp + http_msg.data+8], ' '
  291.         jne     .invalid_header
  292.         DEBUGF  1, "Header seems valid.\n"
  293.  
  294.         lea     esi, [ebp + http_msg.data+9]
  295.         xor     eax, eax
  296.         xor     ebx, ebx
  297.         mov     ecx, 3
  298.   .statusloop:
  299.         lodsb
  300.         sub     al, '0'
  301.         jb      .invalid_header
  302.         cmp     al, 9
  303.         ja      .invalid_header
  304.         lea     ebx, [ebx + 4*ebx]
  305.         shl     ebx, 1
  306.         add     ebx, eax
  307.         dec     ecx
  308.         jnz     .statusloop
  309.         mov     [ebp + http_msg.status], ebx
  310.         DEBUGF  1, "Status: %u\n", ebx
  311.  
  312. ; Now, convert all header names to lowercase.
  313. ; This way, it will be much easier to find certain header fields, later on.
  314.  
  315.         lea     esi, [ebp + http_msg.data]
  316.         mov     ecx, [ebp + http_msg.header_length]
  317.   .need_newline:
  318.         inc     esi
  319.         dec     ecx
  320.         jz      .convert_done
  321.         cmp     byte[esi], 10
  322.         jne     .need_newline
  323. ; Ok, we have a newline, a line beginning with space or tabs has no header fields.
  324.  
  325.         inc     esi
  326.         dec     ecx
  327.         jz      .convert_done
  328.         cmp     byte[esi], ' '
  329.         je      .need_newline
  330.         cmp     byte[esi], 9    ; horizontal tab
  331.         je      .need_newline
  332.         jmp     .convert_loop
  333.   .next_char:
  334.         inc     esi
  335.         dec     ecx
  336.         jz      .convert_done
  337.   .convert_loop:
  338.         cmp     byte[esi], ':'
  339.         je      .need_newline
  340.         cmp     byte[esi], 'A'
  341.         jb      .next_char
  342.         cmp     byte[esi], 'Z'
  343.         ja      .next_char
  344.         or      byte[esi], 0x20 ; convert to lowercase
  345.         jmp     .next_char
  346.   .convert_done:
  347.         mov     byte[esi-1], 0
  348.         lea     esi, [ebp + http_msg.data]
  349.         DEBUGF  1, "Header names converted to lowercase:\n%s\n", esi
  350.  
  351. ; Check for content-length header field.
  352.         stdcall find_header_field, ebp, str_cl
  353.         test    eax, eax
  354.         jz      .no_content
  355.         or      [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
  356.  
  357.         xor     edx, edx
  358.   .cl_loop:
  359.         movzx   ebx, byte[eax]
  360.         inc     eax
  361.         cmp     bl, 10
  362.         je      .cl_ok
  363.         cmp     bl, 13
  364.         je      .cl_ok
  365.         cmp     bl, ' '
  366.         je      .cl_ok
  367.         sub     bl, '0'
  368.         jb      .invalid_header
  369.         cmp     bl, 9
  370.         ja      .invalid_header
  371.         lea     edx, [edx + edx*4]      ; edx = edx*10
  372.         shl     edx, 1                  ;
  373.         add     edx, ebx
  374.         jmp     .cl_loop
  375.  
  376.   .cl_ok:
  377.         mov     [ebp + http_msg.content_length], edx
  378.         DEBUGF  1, "Content-length: %u\n", edx
  379.  
  380. ; Resize buffer according to content-length.
  381.         mov     eax, [ebp + http_msg.header_length]
  382.         add     eax, [ebp + http_msg.content_length]
  383.         add     eax, http_msg.data
  384.  
  385.         mov     ecx, eax
  386.         sub     ecx, [ebp + http_msg.write_ptr]
  387.         mov     [ebp + http_msg.buffer_length], ecx
  388.  
  389.         invoke  mem.realloc, ebp, eax
  390.         or      eax, eax
  391.         jz      .no_ram
  392.         jmp     .header_parsed  ; hooray!
  393.  
  394.   .no_content:
  395.         DEBUGF  1, "Content-length not found.\n"
  396.  
  397. ; We didnt find 'content-length', maybe server is using chunked transfer encoding?
  398. ; Try to find 'transfer-encoding' header.
  399.         stdcall find_header_field, ebp, str_te
  400.         test    eax, eax
  401.         jz      .invalid_header
  402.  
  403.         mov     ebx, dword[eax]
  404.         or      ebx, 0x20202020
  405.         cmp     ebx, 'chun'
  406.         jne     .invalid_header
  407.         mov     ebx, dword[eax+4]
  408.         or      ebx, 0x00202020
  409.         and     ebx, 0x00ffffff
  410.         cmp     ebx, 'ked'
  411.         jne     .invalid_header
  412.  
  413.         or      [ebp + http_msg.flags], FLAG_CHUNKED
  414.         DEBUGF  1, "Transfer type is: chunked\n"
  415.  
  416. ; Set chunk pointer where first chunk should begin.
  417.         lea     eax, [ebp + http_msg.data]
  418.         add     eax, [ebp + http_msg.header_length]
  419.         mov     [ebp + http_msg.chunk_ptr], eax
  420.  
  421.   .chunk_loop:
  422.         mov     ecx, [ebp + http_msg.write_ptr]
  423.         sub     ecx, [ebp + http_msg.chunk_ptr]
  424.         jb      .need_more_data_chunked
  425.  
  426. ; TODO: make sure we have the complete chunkline header
  427.         mov     esi, [ebp + http_msg.chunk_ptr]
  428.         xor     ebx, ebx
  429.   .chunk_hexloop:
  430.         lodsb
  431.         sub     al, '0'
  432.         jb      .chunk_
  433.         cmp     al, 9
  434.         jbe     .chunk_hex
  435.         sub     al, 'A' - '0' - 10
  436.         jb      .chunk_
  437.         cmp     al, 15
  438.         jbe     .chunk_hex
  439.         sub     al, 'a' - 'A'
  440.         cmp     al, 15
  441.         ja      .chunk_
  442.   .chunk_hex:
  443.         shl     ebx, 4
  444.         add     bl, al
  445.         jmp     .chunk_hexloop
  446.   .chunk_:
  447.         DEBUGF  1, "got chunk of %u bytes\n", ebx
  448. ; If chunk size is 0, all chunks have been received.
  449.         test    ebx, ebx
  450.         jz      .got_all_data_chunked           ; last chunk, hooray! FIXME: what if it wasnt a valid hex number???
  451.         mov     edi, [ebp + http_msg.chunk_ptr] ; we'll need this in about 25 lines...
  452.         add     [ebp + http_msg.chunk_ptr], ebx
  453.  
  454. ; Chunkline ends with a CR, LF or simply LF
  455.   .end_of_chunkline?:           ; FIXME: buffer overflow possible!
  456.         cmp     al, 10
  457.         je      .end_of_chunkline
  458.         lodsb
  459.         jmp     .end_of_chunkline?
  460.  
  461.   .end_of_chunkline:
  462. ; Realloc buffer, make it 'chunksize' bigger.
  463.         mov     eax, [ebp + http_msg.buffer_length]
  464.         add     eax, ebx
  465.         invoke  mem.realloc, ebp, eax
  466.         or      eax, eax
  467.         jz      .no_ram
  468.         add     [ebp + http_msg.buffer_length], ebx
  469.  
  470. ; Update write ptr
  471.         mov     eax, esi
  472.         sub     eax, edi
  473.         sub     [ebp + http_msg.write_ptr], eax
  474.  
  475. ; Now move all received data to the left (remove chunk header).
  476. ; Update content_length accordingly.
  477.         mov     ecx, [ebp + http_msg.write_ptr]
  478.         sub     ecx, esi
  479.         add     [ebp + http_msg.content_length], ecx
  480.         rep     movsb
  481.         jmp     .chunk_loop
  482.  
  483. ; Check if we got all the data.
  484.   .header_parsed:
  485.         mov     eax, [ebp + http_msg.header_length]
  486.         add     eax, [ebp + http_msg.content_length]
  487.         cmp     eax, [ebp + http_msg.buffer_length]
  488.         je      .got_all_data
  489.   .need_more_data:
  490.         popa
  491.         xor     eax, eax
  492.         dec     eax
  493.         ret
  494.  
  495.   .need_more_data_chunked:
  496.         add     [ebp + http_msg.content_length], eax
  497.         popa
  498.         xor     eax, eax
  499.         dec     eax
  500.         ret
  501.  
  502.   .got_all_data_chunked:
  503.         mov     eax, [ebp + http_msg.chunk_ptr]
  504.         sub     eax, [ebp + http_msg.header_length]
  505.         sub     eax, http_msg.data
  506.         sub     eax, ebp
  507.         mov     [ebp + http_msg.content_length], eax
  508.  
  509.   .got_all_data:
  510.         DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_length]
  511.         or      [ebp + http_msg.flags], FLAG_GOT_DATA
  512.         mcall   close, [ebp + http_msg.socket]
  513.         popa
  514.         xor     eax, eax
  515.         ret
  516.  
  517.   .check_socket:
  518.         cmp     ebx, EWOULDBLOCK
  519.         je      .need_more_data
  520.         DEBUGF  1, "ERROR: socket error %u\n", ebx
  521.  
  522.         or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
  523.         popa
  524.         xor     eax, eax
  525.         ret
  526.  
  527.   .invalid_header:
  528.         DEBUGF  1, "ERROR: invalid header\n"
  529.         or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
  530.         popa
  531.         xor     eax, eax
  532.         ret
  533.  
  534.   .no_ram:
  535.         DEBUGF  1, "ERROR: out of RAM\n"
  536.         or      [ebp + http_msg.flags], FLAG_NO_RAM
  537.         popa
  538.         xor     eax, eax
  539.         ret
  540.  
  541. endp
  542.  
  543.  
  544.  
  545. ;;================================================================================================;;
  546. proc find_header_field identifier, headername ;///////////////////////////////////////////////////;;
  547. ;;------------------------------------------------------------------------------------------------;;
  548. ;?                                                                                                ;;
  549. ;;------------------------------------------------------------------------------------------------;;
  550. ;> _                                                                                              ;;
  551. ;;------------------------------------------------------------------------------------------------;;
  552. ;< eax = -1 (error) / 0                                                                           ;;
  553. ;;================================================================================================;;
  554.         push    ebx ecx edx esi edi
  555.  
  556.         DEBUGF  1, "Find header field: %s\n", [headername]
  557.  
  558.         mov     ebx, [identifier]
  559.         lea     edx, [ebx + http_msg.data]
  560.         mov     ecx, edx
  561.         add     ecx, [ebx + http_msg.header_length]
  562.  
  563.   .restart:
  564.         mov     esi, [headername]
  565.         mov     edi, edx
  566.   .loop:
  567.         cmp     edi, ecx
  568.         jae     .fail
  569.         lodsb
  570.         scasb
  571.         je      .loop
  572.         test    al, al
  573.         jz      .done?
  574.   .next:
  575.         inc     edx
  576.         jmp     .restart
  577.  
  578.   .not_done:
  579.         inc     edi
  580.   .done?:
  581.         cmp     byte[edi-1], ':'
  582.         je      .almost_done
  583.         cmp     byte[edi-1], ' '
  584.         je      .not_done
  585.         cmp     byte[edi-1], 9  ; tab
  586.         je      .not_done
  587.  
  588.         jmp     .next
  589.  
  590.   .almost_done:                 ; FIXME: buffer overflow?
  591.         dec     edi
  592.         DEBUGF  1, "Found header field\n"
  593.   .spaceloop:
  594.         inc     edi
  595.         cmp     byte[edi], ' '
  596.         je      .spaceloop
  597.         cmp     byte[edi], 9    ; tab
  598.         je      .spaceloop
  599.  
  600.         mov     eax, edi
  601.         pop     edi esi edx ecx ebx
  602.         ret
  603.  
  604.   .fail:
  605.         pop     edi esi edx ecx ebx
  606.         xor     eax, eax
  607.         ret
  608.  
  609. endp
  610.  
  611.  
  612. ; internal procedures start here:
  613.  
  614.  
  615. ;;================================================================================================;;
  616. proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
  617. ;;------------------------------------------------------------------------------------------------;;
  618. ;?                                                                                                ;;
  619. ;;------------------------------------------------------------------------------------------------;;
  620. ;> _                                                                                              ;;
  621. ;;------------------------------------------------------------------------------------------------;;
  622. ;< eax = -1 (error) / 0                                                                           ;;
  623. ;;================================================================================================;;
  624.  
  625. locals
  626.         urlsize         dd ?
  627.         hostname        dd ?
  628.         pageaddr        dd ?
  629. endl
  630.  
  631.         DEBUGF  1, "parsing URL: %s\n", [URL]
  632.  
  633. ; remove any leading protocol text
  634.         mov     esi, [URL]
  635.         mov     ecx, URLMAXLEN
  636.         mov     ax, '//'
  637.   .loop1:
  638.         cmp     byte[esi], 0            ; end of URL?
  639.         je      .url_ok                 ; yep, so not found
  640.         cmp     [esi], ax
  641.         je      .skip_proto
  642.         inc     esi
  643.         dec     ecx
  644.         jnz     .loop1
  645.  
  646.         DEBUGF  1, "Invalid URL\n"
  647.         xor     eax, eax
  648.         ret
  649.  
  650.   .skip_proto:
  651.         inc     esi                     ; skip the two '/'
  652.         inc     esi
  653.         mov     [URL], esi              ; update pointer so it skips protocol
  654.         jmp     .loop1                  ; we still need to find the length of the URL
  655.  
  656.   .url_ok:
  657.         sub     esi, [URL]              ; calculate total length of URL
  658.         mov     [urlsize], esi
  659.  
  660.  
  661. ; now look for page delimiter - it's a '/' character
  662.         mov     ecx, esi                ; URL length
  663.         mov     edi, [URL]
  664.         mov     al, '/'
  665.         repne   scasb
  666.         jne     @f
  667.         dec     edi                     ; return one char, '/' must be part of the pageaddr
  668.         inc     ecx                     ;
  669.   @@:
  670.         push    ecx edi                 ; remember the pointer and length of pageaddr
  671.  
  672.         mov     ecx, edi
  673.         sub     ecx, [URL]
  674.         inc     ecx                     ; we will add a 0 byte at the end
  675.         invoke  mem.alloc, ecx
  676.         or      eax, eax
  677.         jz      .no_mem
  678.  
  679.         mov     [hostname], eax         ; copy hostname to buffer
  680.         mov     edi, eax
  681.         mov     esi, [URL]
  682.         dec     ecx
  683.         rep     movsb
  684.         xor     al, al
  685.         stosb
  686.  
  687.         mov     [pageaddr], str_slash   ; assume there is no pageaddr
  688.         pop     esi ecx
  689.         test    ecx, ecx
  690.         jz      .no_page
  691.         inc     ecx                     ; we will add a 0 byte at the end
  692.         invoke  mem.alloc, ecx
  693.         or      eax, eax
  694.         jz      .no_mem
  695.  
  696.         mov     [pageaddr], eax         ; copy pageaddr to buffer
  697.         mov     edi, eax
  698.         dec     ecx
  699.         rep     movsb
  700.         xor     al, al
  701.         stosb
  702.   .no_page:
  703.  
  704.         mov     eax, [hostname]
  705.         mov     ebx, [pageaddr]
  706.  
  707.         DEBUGF  1, "hostname: %s\n", eax
  708.         DEBUGF  1, "pageaddr: %s\n", ebx
  709.  
  710.         ret
  711.  
  712.   .no_mem:
  713.         xor     eax, eax
  714.         ret
  715.  
  716. endp
  717.  
  718.  
  719.  
  720.  
  721.  
  722. ;;================================================================================================;;
  723. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  724. ;;================================================================================================;;
  725. ;! Imported functions section                                                                     ;;
  726. ;;================================================================================================;;
  727. ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
  728. ;;================================================================================================;;
  729.  
  730.  
  731. align 16
  732. @IMPORT:
  733.  
  734. library \
  735.         libini, 'libini.obj', \
  736.         network, 'network.obj'
  737.  
  738. import  libini, \
  739.         ini.get_str, 'ini_get_str', \
  740.         ini.get_int, 'ini_get_int'
  741.  
  742. import  network,\
  743.         getaddrinfo, 'getaddrinfo',\
  744.         freeaddrinfo,  'freeaddrinfo',\
  745.         inet_ntoa, 'inet_ntoa'
  746.  
  747. ;;===========================================================================;;
  748. ;;///////////////////////////////////////////////////////////////////////////;;
  749. ;;===========================================================================;;
  750. ;! Exported functions section                                                ;;
  751. ;;===========================================================================;;
  752. ;;///////////////////////////////////////////////////////////////////////////;;
  753. ;;===========================================================================;;
  754.  
  755.  
  756. align 4
  757. @EXPORT:
  758. export  \
  759.         lib_init                , 'lib_init'            , \
  760.         0x00010001              , 'version'             , \
  761.         HTTP_get                , 'get'                 , \
  762.         find_header_field       , 'find_header_field'   , \
  763.         HTTP_process            , 'process'
  764.  
  765. ;        HTTP_head               , 'head'                , \
  766. ;        HTTP_post               , 'post'                , \
  767. ;        HTTP_put                , 'put'                 , \
  768. ;        HTTP_delete             , 'delete'              , \
  769. ;        HTTP_trace              , 'trace'               , \
  770. ;        HTTP_connect            , 'connect'             , \
  771.  
  772.  
  773.  
  774. section '.data' data readable writable align 16
  775.  
  776. inifile         db '/sys/settings/network.ini', 0
  777.  
  778. sec_proxy:
  779. key_proxy       db 'proxy', 0
  780. key_proxyport   db 'port', 0
  781. key_user        db 'user', 0
  782. key_password    db 'password', 0
  783.  
  784. str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
  785.   .length       = $ - str_http11
  786. str_close       db 13, 10, 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
  787.   .length       = $ - str_close
  788. str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
  789.   .length       = $ - str_proxy_auth
  790.  
  791. base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  792.                 db '0123456789+/'
  793.  
  794. str_cl          db 'content-length', 0
  795. str_slash       db '/', 0
  796. str_te          db 'transfer-encoding', 0
  797.  
  798. include_debug_strings
  799.  
  800. ; uninitialized data
  801. mem.alloc       dd ?
  802. mem.free        dd ?
  803. mem.realloc     dd ?
  804. dll.load        dd ?
  805.  
  806. proxyAddr       rb 256
  807. proxyUser       rb 256
  808. proxyPassword   rb 256
  809. proxyPort       dd ?