Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2009-2013. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  downloader.asm - HTTP client for KolibriOS                     ;;
  7. ;;                                                                 ;;
  8. ;;  Based on HTTPC.asm for menuetos by ville turjanmaa             ;;
  9. ;;                                                                 ;;
  10. ;;  Programmers: Barsuk, Clevermouse, Marat Zakiyanov,             ;;
  11. ;;      Kirill Lipatov, dunkaist, HidnPlayr                        ;;
  12. ;;                                                                 ;;
  13. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  14. ;;             Version 2, June 1991                                ;;
  15. ;;                                                                 ;;
  16. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  17.  
  18. URLMAXLEN               = 1024
  19. BUFFERSIZE              = 4096
  20.  
  21. __DEBUG__       = 1
  22. __DEBUG_LEVEL__ = 2
  23.  
  24. format binary as ""
  25.  
  26. use32
  27.         org     0x0
  28.  
  29.         db      'MENUET01'      ; header
  30.         dd      0x01            ; header version
  31.         dd      START           ; entry point
  32.         dd      IM_END          ; image size
  33.         dd      I_END+0x100     ; required memory
  34.         dd      I_END+0x100     ; esp
  35.         dd      params          ; I_PARAM
  36.         dd      0x0             ; I_Path
  37.  
  38. include '../macros.inc'
  39. include '../proc32.inc'
  40. include '../network.inc'
  41. include '../../develop/libraries/box_lib/trunk/box_lib.mac'
  42. include '../dll.inc'
  43. include '../debug-fdo.inc'
  44.  
  45. START:
  46.  
  47.         mcall   68, 11                  ; init heap so we can allocate memory dynamically
  48.  
  49.         mcall   40, EV_STACK
  50.  
  51. ; load libraries
  52.         stdcall dll.Load, @IMPORT
  53.         test    eax, eax
  54.         jnz     exit
  55.  
  56. ; prepare webAddr area
  57.         mov     al, ' '
  58.         mov     edi, webAddr
  59.         mov     ecx, URLMAXLEN
  60.         rep     stosb
  61.         xor     eax, eax
  62.         stosb
  63.  
  64. ; prepare document area
  65.         mov     al, '/'
  66.         mov     edi, document
  67.         stosb
  68.         mov     al, ' '
  69.         mov     ecx, URLMAXLEN-1
  70.         rep     stosb
  71.  
  72.         call    load_settings
  73.         cmp     byte[params], 0
  74.         je      prepare_event   ;red
  75.  
  76. ; we have an url
  77.         mov     edi, document_user
  78.         mov     al, ' '
  79.         mov     ecx, URLMAXLEN
  80.         rep     stosb
  81.        
  82.         mov     esi, params
  83.         mov     edi, document_user
  84.  
  85. ; copy untill space or 0
  86.   .copy_param:
  87.         mov     al, [esi]
  88.         test    al, al
  89.         jz      .done
  90.  
  91.         cmp     al, ' '
  92.         jz      .done_inc
  93.  
  94.         mov     [edi], al
  95.         inc     esi
  96.         inc     edi
  97.         jmp     .copy_param
  98.  
  99.   .done_inc:
  100.  
  101. ; url is followed by shared memory name.
  102.         inc     esi
  103.   .done:
  104.         mov     [shared_name], esi
  105.         jmp     download
  106.  
  107. prepare_event:
  108. ; Report events
  109. ; Stack 8 + defaults
  110.         mcall   40, 10100111b
  111.  
  112. red:    ; redraw
  113.         call    draw_window
  114.  
  115. still:
  116.         cmp     byte [params], 0
  117.         jne     exit
  118.  
  119.         mcall   10      ; wait here for event
  120.         cmp     eax, 1  ; redraw request ?
  121.         je      red
  122.  
  123.         cmp     eax, 2  ; key in buffer ?
  124.         je      key
  125.  
  126.         cmp     eax, 3  ; button in buffer ?
  127.         je      button
  128.        
  129.         cmp     eax, 6  ; mouse in buffer ?
  130.         je      mouse
  131.  
  132.         jmp     still
  133.  
  134.  
  135. key:
  136.         mcall   2       ; read key
  137.  
  138.         stdcall [edit_box_key], dword edit1
  139.  
  140.         cmp     ax, 13 shl 8
  141.         je      download
  142.        
  143.         jmp     still
  144.        
  145. button:
  146.  
  147.         mcall   17      ; get id
  148.         cmp     ah, 26
  149.         jne     @f
  150.         call    save_to_file
  151.         jmp     still
  152.   @@:
  153.         cmp     ah, 1   ; button id=1 ?
  154.         je      exit
  155.  
  156.         jmp     download
  157.  
  158. mouse:
  159.         stdcall [edit_box_mouse], edit1
  160.         jmp     still
  161.  
  162. exit:
  163.         or      eax, -1  ; close this program
  164.         mcall
  165.  
  166. download:
  167.  
  168.         DEBUGF  1, "Starting download\n"
  169.  
  170.         call    parse_url
  171.         call    open_socket
  172.         call    send_request
  173.  
  174.         mcall   68, 12, BUFFERSIZE
  175.         mov     [buf_ptr], eax
  176.         mov     [buf_size], 0
  177.  
  178.         call    read_incoming_data
  179.  
  180.         mcall   close, [socketnum]
  181.  
  182.         call    parse_result
  183.         call    save
  184.  
  185.         mcall   68, 13, [final_buffer]
  186.  
  187.         jmp     still
  188.  
  189.  
  190. save:
  191.  
  192.         mov     ecx, [shared_name]
  193.         test    ecx, ecx
  194.         jz      @f
  195.         cmp     [ecx], byte 0
  196.         jnz     save_in_shared
  197.     @@:
  198.  
  199.         call    save_to_file
  200.  
  201. ; if called from command line, then exit
  202.         cmp     byte[params], 0
  203.         jne     exit
  204.  
  205.         ret
  206.  
  207. save_in_shared:
  208.  
  209.         mov     esi, 1   ; SHM_OPEN+SHM_WRITE
  210.         mcall   68, 22
  211.         test    eax, eax
  212.         jz      exit
  213.  
  214.         sub     edx, 4
  215.         jbe     exit
  216.  
  217.         mov     ecx, [final_size]
  218.         cmp     ecx, edx
  219.         jb      @f
  220.  
  221.         mov     ecx, edx
  222.     @@:
  223.         mov     [eax], ecx
  224.         lea     edi, [eax+4]
  225.         mov     esi, [final_buffer]
  226.         mov     edx, ecx
  227.         shr     ecx, 2
  228.         rep     movsd
  229.         mov     ecx, edx
  230.         and     ecx, 3
  231.         rep     movsb
  232.  
  233.         jmp     exit
  234.  
  235.  
  236. ;****************************************************************************
  237. ;    Function
  238. ;       save_to_file
  239. ;
  240. ;   Description
  241. ;
  242. ;
  243. ;****************************************************************************
  244.  
  245. save_to_file:
  246.  
  247.         DEBUGF  2, "Saving to file\n"
  248.         mcall   70, fileinfo
  249.  
  250.         mov     ecx, [sc.work_text]
  251.         or      ecx, 0x80000000
  252.         mcall   4, <10, 93>, , download_complete
  253.  
  254.         ret
  255.  
  256.  
  257. ;****************************************************************************
  258. ;    Function
  259. ;       send_request
  260. ;
  261. ;   Description
  262. ;       Transmits the GET request to the server.
  263. ;       This is done as GET then URL then HTTP/1.1', 13, 10, 13, 10 in 3 packets
  264. ;
  265. ;****************************************************************************
  266. send_request:
  267.  
  268.         DEBUGF  1, "Sending request\n"
  269.  
  270.         mov     esi, string0
  271.         mov     edi, request
  272.         movsd
  273. ; If proxy is used, make absolute URI - prepend http://<host>
  274.         cmp     byte[proxyAddr], 0
  275.         jz      .noproxy
  276.         mov     dword[edi], 'http'
  277.         mov     byte[edi+4], ':'
  278.         mov     word[edi+5], '//'
  279.         add     edi, 7
  280.         mov     esi, webAddr
  281.  
  282.   .copy_host_loop:
  283.         lodsb
  284.         cmp     al, ' '
  285.         jz      .noproxy
  286.         stosb
  287.         jmp     .copy_host_loop
  288.  
  289.   .noproxy:
  290.         xor     edx, edx ; 0
  291.  
  292.   .next_edx:
  293. ; Determine the length of the url to send in the GET request
  294.         mov     al, [edx+document]
  295.         cmp     al, ' '
  296.         jbe     .document_done
  297.         mov     [edi], al
  298.         inc     edi
  299.         inc     edx
  300.         jmp     .next_edx
  301.  
  302.   .document_done:
  303.         mov     esi, stringh
  304.         mov     ecx, stringh_end-stringh
  305.         rep     movsb
  306.         xor     edx, edx ; 0
  307.  
  308.   .webaddr_next:
  309.         mov     al, [webAddr + edx]
  310.         cmp     al, ' '
  311.         jbe     .webaddr_done
  312.         mov     [edi], al
  313.         inc     edi
  314.         inc     edx
  315.         jmp     .webaddr_next
  316.  
  317.   .webaddr_done:
  318.         cmp     byte[proxyUser], 0
  319.         jz      @f
  320.         call    append_proxy_auth_header
  321.     @@:
  322.         mov     esi, connclose
  323.         mov     ecx, connclose_end-connclose
  324.         rep     movsb
  325.  
  326.         pusha  
  327.         mov     eax, 63
  328.         mov     ebx, 1
  329.         mov     edx, request
  330.     @@:
  331.         mov     cl, [edx]
  332.         cmp     edx, edi
  333.         jz      @f
  334.         mcall
  335.         inc     edx
  336.         jmp     @b
  337.     @@:
  338.         popa
  339.  
  340.         mov     esi, edi
  341.         sub     esi, request    ; length
  342.         xor     edi, edi        ; flags
  343.         mcall   send, [socketnum], request  ;' HTTP/1.1 .. '
  344.         ret
  345.  
  346. ;****************************************************************************
  347. ;    Function
  348. ;       read_incoming_data
  349. ;
  350. ;   Description
  351. ;       receive the web page from the server, storing it without processing
  352. ;
  353. ;****************************************************************************
  354. read_incoming_data:
  355.  
  356.         DEBUGF  1, "Reading incoming data\n"
  357.  
  358.         mov     eax, [buf_ptr]
  359.         mov     [pos], eax
  360.  
  361.   .read:
  362.         mcall   23, 100         ; 1 second timeout
  363.   .read_dontwait:
  364.         mcall   recv, [socketnum], [pos], BUFFERSIZE, 0
  365.         inc     eax             ; -1 = error (socket closed?)
  366.         jz      .no_more_data
  367.         dec     eax             ; 0 bytes...
  368.         jz      .read           ; timeout
  369.  
  370.         DEBUGF  1, "Got chunk of %u bytes\n", eax
  371.  
  372.         add     [buf_size], eax
  373.         add     [pos], eax
  374.         push    eax
  375.         mov     ecx, [buf_size]
  376.         add     ecx, BUFFERSIZE
  377.         mcall   68, 20, , [buf_ptr]     ; reallocate memory block (make bigger)
  378.         ; TODO: parse header and resize buffer only once
  379.         pop     eax
  380.  
  381.         cmp     eax, BUFFERSIZE
  382.         je      .read_dontwait
  383.         jmp     .read
  384.        
  385.   .no_more_data:
  386.         mov     eax, [buf_ptr]
  387.         sub     [pos], eax
  388.  
  389.         DEBUGF  1, "No more data\n"
  390.  
  391.         ret
  392.        
  393.  
  394.        
  395. ; this function cuts header, and removes chunk sizes if doc is chunked
  396. ; in: buf_ptr, pos; out: buf_ptr, pos.
  397.        
  398. parse_result:
  399.  
  400.         mov     edi, [buf_ptr]
  401.         mov     edx, [pos]
  402. ;        mov     [buf_size], edx
  403. ;       mcall   70, fileinfo_tmp
  404.         DEBUGF  1, "Parsing result (%u bytes)\n", edx
  405.  
  406. ; first, find end of headers
  407.   .next_byte:
  408.         cmp     dword[edi], 0x0d0a0d0a  ; ìíå ëåíü ÷èòàòü ñòàíäàðò, ïóñòü áóäóò îáà âàðèàíòà
  409.         je      .end_of_headers
  410.         cmp     dword[edi], 0x0a0d0a0d
  411.         je      .end_of_headers
  412.         inc     edi
  413.         dec     edx
  414.         jne     .next_byte
  415.         DEBUGF  1, "Uh-oh, there's no end of header!\n"
  416. ; no end of headers. it's an error. let client see all those headers.
  417.         ret
  418.  
  419.   .end_of_headers:
  420. ; here we look at headers and search content-length or transfer-encoding headers
  421.         DEBUGF  1, "Found end of header\n"
  422.  
  423.         sub     edi, [buf_ptr]
  424.         add     edi, 4
  425.         mov     [body_pos], edi  ; store position where document body starts
  426.         mov     [is_chunked], 0
  427. ; find content-length in headers
  428. ; not good method, but should work for 'Content-Length:'
  429.         mov     esi, [buf_ptr]
  430.         mov     edi, s_contentlength
  431.         mov     ebx, [body_pos]
  432.         xor     edx, edx ; 0
  433.   .cl_next:
  434.         mov     al, [esi]
  435.         cmp     al, [edi + edx]
  436.         jne     .cl_fail
  437.         inc     edx
  438.         cmp     edx, len_contentlength
  439.         je      .cl_found
  440.         jmp     .cl_incr
  441.   .cl_fail:
  442.         xor     edx, edx ; 0
  443.   .cl_incr:
  444.         inc     esi
  445.         dec     ebx
  446.         je      .cl_error
  447.         jmp     .cl_next
  448.   .cl_error:
  449.         DEBUGF  1, "content-length not found\n"
  450.  
  451. ; find 'chunked'
  452. ; äà, ÿ êîïèðóþ êîä, ýòî óæàñíî, íî ìíå õî÷åòñÿ, ÷òîáû ïîñêîðåå çàðàáîòàëî
  453. ; à òàì óæ îòðåôàêòîðþ
  454.         mov     esi, [buf_ptr]
  455.         mov     edi, s_chunked
  456.         mov     ebx, [body_pos]
  457.         xor     edx, edx ; 0
  458.  
  459.   .ch_next:
  460.         mov     al, [esi]
  461.         cmp     al, [edi + edx]
  462.         jne     .ch_fail
  463.         inc     edx
  464.         cmp     edx, len_chunked
  465.         je      .ch_found
  466.         jmp     .ch_incr
  467.  
  468.   .ch_fail:
  469.         xor     edx, edx ; 0
  470.  
  471.   .ch_incr:
  472.         inc     esi
  473.         dec     ebx
  474.         je      .ch_error
  475.         jmp     .ch_next
  476.  
  477.   .ch_error:
  478. ; if neither of the 2 headers is found, it's an error
  479. ;       DEBUGF  1, "transfer-encoding: chunked not found\n"
  480.         mov     eax, [pos]
  481.         sub     eax, [body_pos]
  482.         jmp     .write_final_size
  483.  
  484.   .ch_found:
  485.         mov     [is_chunked], 1
  486.         mov     eax, [body_pos]
  487.         add     eax, [buf_ptr]
  488.         sub     eax, 2
  489.         mov     [prev_chunk_end], eax
  490.         jmp     parse_chunks
  491.        
  492.   .cl_found:
  493.         call    read_number     ; eax = number from *esi
  494.         DEBUGF  1, "Content length: %u\n", eax
  495.  
  496.   .write_final_size:
  497.        
  498.         mov     ebx, [buf_size]
  499.         sub     ebx, [body_pos]
  500.         cmp     eax, ebx
  501.         jbe     .size_ok
  502.         sub     eax, ebx
  503.         DEBUGF  2, "%u bytes of data are missing!\n", eax
  504.         mov     eax, ebx
  505.   .size_ok:
  506.         mov     [final_size], eax
  507.  
  508.         mov     ebx, [body_pos]
  509.         add     ebx, [buf_ptr]
  510.         mov     [final_buffer], ebx
  511.  
  512.         ret
  513.        
  514. parse_chunks:
  515.         DEBUGF  1, "parse chunks\n"
  516.         ; we have to look through the data and remove sizes of chunks we see
  517.         ; 1. read size of next chunk
  518.         ; 2. if 0, it's end. if not, continue.
  519.         ; 3. make a good buffer and copy a chunk there
  520.         xor     eax, eax
  521.         mov     [final_buffer], eax      ; 0
  522.         mov     [final_size], eax        ; 0
  523.        
  524. .read_size:
  525.         mov     eax, [prev_chunk_end]
  526.         mov     ebx, eax
  527.         sub     ebx, [buf_ptr]
  528.         mov     edx, eax
  529.         DEBUGF  1, "rs "
  530.         cmp     ebx, [pos]
  531.         jae     chunks_end      ; not good
  532.        
  533.         call    read_hex        ; in: eax=pointer to text. out:eax=hex number, ebx=end of text.
  534.         cmp     eax, 0
  535.         jz      chunks_end
  536.  
  537.         add     ebx, 1
  538.         mov     edx, ebx ; edx = size of size of chunk
  539.        
  540.         add     ebx, eax
  541.         mov     [prev_chunk_end], ebx
  542.        
  543.         DEBUGF  1, "sz "
  544.  
  545. ; do copying: from buf_ptr+edx to final_buffer+prev_final_size count eax
  546. ; realloc final buffer
  547.         push    eax
  548.         push    edx
  549.         push    dword [final_size]
  550.         add     [final_size], eax
  551.         mcall   68, 20, [final_size], [final_buffer]
  552.         mov     [final_buffer], eax
  553.         DEBUGF  1, "re "
  554.         pop     edi
  555.         pop     esi
  556.         pop     ecx
  557. ;       add     [pos], ecx
  558.         add     edi, [final_buffer]
  559.         DEBUGF  1, "cp "
  560.  
  561.         rep     movsb
  562.         jmp     .read_size
  563.        
  564. chunks_end:
  565.         DEBUGF  1, "chunks end\n"
  566.         mcall   68, 13, [buf_ptr]       ; free old buffer
  567.  
  568.         ret
  569.  
  570. ; reads content-length from [edi+ecx], result in eax
  571. read_number:
  572.         push    ebx
  573.         xor     eax, eax
  574.         xor     ebx, ebx
  575.  
  576.   .next:
  577.         mov     bl, [esi]
  578.  
  579.         cmp     bl, '0'
  580.         jb      .not_number
  581.         cmp     bl, '9'
  582.         ja      .not_number
  583.         sub     bl, '0'
  584.         shl     eax, 1
  585.         lea     eax, [eax + eax * 4]     ; eax *= 10
  586.         add     eax, ebx
  587.  
  588.   .not_number:
  589.         cmp     bl, 13
  590.         je      .done
  591.         inc     esi
  592.         jmp     .next
  593.  
  594.   .done:
  595.         pop     ebx
  596.         ret
  597.        
  598. ; reads hex from eax, result in eax, end of text in ebx
  599. read_hex:
  600.         add     eax, 2
  601.         mov     ebx, eax
  602.         mov     eax, [ebx]
  603.         mov     [deba], eax
  604.  
  605.         xor     eax, eax
  606.         xor     ecx, ecx
  607. .next:
  608.         mov     cl, [ebx]
  609.         inc     ebx
  610.        
  611.         cmp     cl, 0x0d
  612.         jz      .done
  613.  
  614.         or      cl, 0x20
  615.         sub     cl, '0'
  616.         jb      .bad
  617.  
  618.         cmp     cl, 0x9
  619.         jbe     .adding
  620.  
  621.         sub     cl, 'a'-'0'-10
  622.         cmp     cl, 0x0a
  623.         jb      .bad
  624.  
  625.         cmp     cl, 0x0f
  626.         ja      .bad
  627.  
  628. .adding:
  629.         shl     eax, 4
  630.         or      eax, ecx
  631. ;       jmp     .not_number
  632. ;.bad:
  633. .bad:
  634.         jmp     .next
  635. .done:
  636.  
  637.         ret
  638.  
  639. ;****************************************************************************
  640. ;    Function
  641. ;       open_socket
  642. ;
  643. ;   Description
  644. ;       opens the socket
  645. ;
  646. ;****************************************************************************
  647. open_socket:
  648.  
  649.         DEBUGF  1, "opening socket\n"
  650.  
  651.         mov     edx, 80
  652.         cmp     byte [proxyAddr], 0
  653.         jz      @f
  654.         mov     eax, [proxyPort]
  655.         xchg    al, ah
  656.         mov     [server_port], ax
  657.     @@:
  658.  
  659.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  660.         mov     [socketnum], eax
  661.         mcall   connect, [socketnum], sockaddr1, 18
  662.  
  663.         ret
  664.  
  665.  
  666. ;****************************************************************************
  667. ;    Function
  668. ;       parse_url
  669. ;
  670. ;   Description
  671. ;       parses the full url typed in by the user into a web address ( that
  672. ;       can be turned into an IP address by DNS ) and the page to display
  673. ;       DNS will be used to translate the web address into an IP address, if
  674. ;       needed.
  675. ;       url is at document_user and will be space terminated.
  676. ;       web address goes to webAddr and is space terminated.
  677. ;       ip address goes to server_ip
  678. ;       page goes to document and is space terminated.
  679. ;
  680. ;       Supported formats:
  681. ;       <protocol://>address<page>
  682. ;       <protocol> is optional, removed and ignored - only http supported
  683. ;       <address> is required. It can be an ip address or web address
  684. ;       <page> is optional and must start with a leading / character
  685. ;
  686. ;****************************************************************************
  687. parse_url:
  688. ; First, reset destination variables
  689.         mov     al, ' '
  690.         mov     edi, document
  691.         mov     ecx, URLMAXLEN
  692.         rep     stosb
  693.         mov     edi, webAddr
  694.         mov     ecx, URLMAXLEN
  695.         rep     stosb
  696.  
  697.         mov     al, '/'
  698.         mov     [document], al
  699.  
  700.         mov     esi, document_user
  701. ; remove any leading protocol text
  702.         mov     ecx, URLMAXLEN
  703.         mov     ax, '//'
  704.  
  705. pu_000:
  706.         cmp     [esi], byte ' '         ; end of text?
  707.         je      pu_002                  ; yep, so not found
  708.         cmp     [esi], ax
  709.         je      pu_001                  ; Found it, so esi+2 is start
  710.         inc     esi
  711.         loop    pu_000
  712.  
  713. pu_002:
  714. ; not found, so reset esi to start
  715.         mov     esi, document_user-2
  716.  
  717. pu_001:
  718.         add     esi, 2
  719.         mov     ebx, esi ; save address of start of web address
  720.         mov     edi, document_user + URLMAXLEN   ; end of string
  721. ; look for page delimiter - it's a '/' character
  722. pu_003:
  723.         cmp     [esi], byte ' '  ; end of text?
  724.         je      pu_004          ; yep, so none found
  725.         cmp     esi, edi         ; end of string?
  726.         je      pu_004          ; yep, so none found
  727.         cmp     [esi], byte '/'  ; delimiter?
  728.         je      pu_005          ; yep - process it
  729.         inc     esi
  730.         jmp     pu_003
  731.  
  732. pu_005:
  733. ; copy page to document address
  734. ; esi = delimiter
  735.         push    esi
  736.         mov     ecx, edi         ; end of document_user
  737.         mov     edi, document
  738.  
  739. pu_006:
  740.         movsb
  741.         cmp     esi, ecx
  742.         je      pu_007          ; end of string?
  743.         cmp     [esi], byte ' '  ; end of text
  744. ;       je      pu_007          ; äçåí-àññåìáëåð
  745. ;       jmp     pu_006          ; íå íàäî ïëîäèòü ñóùíîñòè ïî íàïðàñíó
  746.         jne     pu_006
  747.  
  748. pu_007:
  749.         pop     esi     ; point esi to '/' delimiter
  750.  
  751. pu_004:
  752. ; copy web address to webAddr
  753. ; start in ebx, end in esi-1
  754.         mov     ecx, esi
  755.         mov     esi, ebx
  756.         mov     edi, webAddr
  757.   @@:
  758.         movsb
  759.         cmp     esi, ecx
  760.         jne     @r
  761.         mov     byte [edi], 0
  762.  
  763. pu_009:
  764. ; For debugging, display resulting strings
  765.         DEBUGF  2, "Downloadng %s\n", document_user
  766.  
  767. ; Look up the ip address, or was it specified?
  768.         mov     al, [proxyAddr]
  769.         cmp     al, 0
  770.         jnz     pu_015
  771.         mov     al, [webAddr]
  772. pu_015:
  773.         cmp     al, '0'
  774.         jb      pu_010  ; Resolve address
  775.         cmp     al, '9'
  776.         ja      pu_010  ; Resolve address
  777.  
  778.         DEBUGF  1, "GotIP\n"
  779.  
  780. ; Convert address
  781. ; If proxy is given, get proxy address instead of server
  782.         mov     esi, proxyAddr-1
  783.         cmp     byte[esi+1], 0
  784.         jne     pu_020
  785.         mov     esi, webAddr-1
  786.  
  787. pu_020:
  788.         mov     edi, server_ip
  789.         xor     eax, eax
  790.  
  791. ip1:
  792.         inc     esi
  793.         cmp     [esi], byte '0'
  794.         jb      ip2
  795.         cmp     [esi], byte '9'
  796.         ja      ip2
  797.         imul    eax, 10
  798.         movzx   ebx, byte [esi]
  799.         sub     ebx, 48
  800.         add     eax, ebx
  801.         jmp     ip1
  802.  
  803. ip2:
  804.         mov     [edi], al
  805.         xor     eax, eax
  806.         inc     edi
  807.         cmp     edi, server_ip+3
  808.         jbe     ip1
  809.         jmp     pu_011
  810.  
  811. pu_010:
  812.         DEBUGF  1, "Resolving %s\n", webAddr
  813.  
  814. ; resolve name
  815.         push    esp     ; reserve stack place
  816.         push    esp     ; fourth parameter
  817.         push    0       ; third parameter
  818.         push    0       ; second parameter
  819.         push    webAddr
  820.         call    [getaddrinfo]
  821.         pop     esi
  822. ; TODO: handle error
  823. ;        test    eax, eax
  824. ;        jnz     .fail_dns
  825.  
  826. ; fill in ip
  827.         mov     eax, [esi + addrinfo.ai_addr]
  828.         mov     eax, [eax + sockaddr_in.sin_addr]
  829.         mov     [server_ip], eax
  830.  
  831.         DEBUGF  1, "Resolved to %u.%u.%u.%u\n", [server_ip]:1, [server_ip + 1]:1, [server_ip + 2]:1, [server_ip + 3]:1
  832.  
  833. pu_011:
  834.  
  835.         ret
  836.  
  837. ;***************************************************************************
  838. ;   Function
  839. ;       load_settings
  840. ;
  841. ;   Description
  842. ;       Load settings from configuration file network.ini
  843. ;
  844. ;***************************************************************************
  845. load_settings:
  846.  
  847.         invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
  848.         invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
  849.         mov     [proxyPort], eax
  850.         invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
  851.         invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
  852.  
  853.         ret
  854.  
  855. ;***************************************************************************
  856. ;   Function
  857. ;       append_proxy_auth_header
  858. ;
  859. ;   Description
  860. ;       Append header to HTTP request for proxy authentification
  861. ;
  862. ;***************************************************************************
  863. append_proxy_auth_header:
  864.         mov     esi, proxy_auth_basic
  865.         mov     ecx, proxy_auth_basic_end - proxy_auth_basic
  866.         rep     movsb
  867. ; base64-encode string <user>:<password>
  868.         mov     esi, proxyUser
  869.  
  870. apah000:
  871.         lodsb
  872.         test    al, al
  873.         jz      apah001
  874.         call    encode_base64_byte
  875.         jmp     apah000
  876.  
  877. apah001:
  878.         mov     al, ':'
  879.         call    encode_base64_byte
  880.         mov     esi, proxyPassword
  881.  
  882. apah002:
  883.         lodsb
  884.         test    al, al
  885.         jz      apah003
  886.         call    encode_base64_byte
  887.         jmp     apah002
  888.  
  889. apah003:
  890.         call    encode_base64_final
  891.         ret
  892.  
  893. encode_base64_byte:
  894.         inc     ecx
  895.         shl     edx, 8
  896.         mov     dl, al
  897.         cmp     ecx, 3
  898.         je      ebb001
  899.         ret
  900.  
  901. ebb001:
  902.         shl     edx, 8
  903.         inc     ecx
  904.  
  905. ebb002:
  906.         rol     edx, 6
  907.         xor     eax, eax
  908.         xchg    al, dl
  909.         mov     al, [base64_table+eax]
  910.         stosb
  911.         loop    ebb002
  912.         ret
  913.  
  914. encode_base64_final:
  915.         mov     al, 0
  916.         test    ecx, ecx
  917.         jz      ebf000
  918.         call    encode_base64_byte
  919.         test    ecx, ecx
  920.         jz      ebf001
  921.         call    encode_base64_byte
  922.         mov     byte [edi-2], '='
  923.  
  924. ebf001:
  925.         mov     byte [edi-1], '='
  926.  
  927. ebf000:
  928.         ret
  929.  
  930. ;   *********************************************
  931. ;   *******  WINDOW DEFINITIONS AND DRAW ********
  932. ;   *********************************************
  933.  
  934. draw_window:
  935.  
  936.         mcall   12, 1
  937.  
  938.         mcall   48, 3, sc, 40 ;get system colors
  939.  
  940.         mov     edx, [sc.work]
  941.         or      edx, 0x34000000
  942.         mcall   0, <50, 370>, <350, 140>, , 0, title   ;draw window
  943.        
  944.         mov     ecx, [sc.work_text]
  945.         or      ecx, 80000000h
  946.         mcall   4, <14, 14>, , type_pls ;"URL:"
  947.  
  948.         edit_boxes_set_sys_color edit1, editboxes_end, sc
  949.         stdcall [edit_box_draw], edit1
  950.  
  951. ; RELOAD
  952.         mcall   8, <90, 68>, <54, 16>, 22, [sc.work_button]
  953. ; STOP
  954.         mcall   , <166, 50>, <54, 16>, 24
  955. ; SAVE
  956.         mcall   , <224, 54>, , 26
  957. ; BUTTON TEXT
  958.         mov     ecx, [sc.work_button_text]
  959.         or      ecx, 80000000h
  960.         mcall   4, <102, 59>, , button_text
  961.  
  962.         mcall   12, 2 ; end window redraw
  963.         ret
  964.  
  965.  
  966. ;-----------------------------------------------------------------------------
  967. ; Data area
  968. ;-----------------------------------------------------------------------------
  969. align   4
  970. @IMPORT:
  971.  
  972. library libini, 'libini.obj', \
  973.         box_lib, 'box_lib.obj', \
  974.         network, 'network.obj'
  975.  
  976. import  libini, \
  977.         ini.get_str, 'ini_get_str', \
  978.         ini.get_int, 'ini_get_int'
  979.  
  980. import  box_lib, \
  981.         edit_box_draw, 'edit_box', \
  982.         edit_box_key, 'edit_box_key', \
  983.         edit_box_mouse, 'edit_box_mouse'
  984.  
  985. import  network,\
  986.         getaddrinfo,    'getaddrinfo',\
  987.         freeaddrinfo,   'freeaddrinfo',\
  988.         inet_ntoa,      'inet_ntoa'
  989.  
  990. ;---------------------------------------------------------------------
  991. fileinfo        dd 2, 0, 0
  992. final_size      dd 0
  993. final_buffer    dd 0
  994.                 db '/rd/1/.download', 0
  995.        
  996. body_pos        dd 0
  997. buf_size        dd 0
  998. buf_ptr         dd 0
  999.  
  1000. deba            dd 0
  1001.                 db 0
  1002.  
  1003. ;---------------------------------------------------------------------
  1004.  
  1005. mouse_dd        dd 0
  1006. edit1           edit_box 295, 48, 10, 0xffffff, 0xff, 0x80ff, 0, 0x8000, URLMAXLEN, document_user, mouse_dd, ed_focus+ed_always_focus, 7, 7
  1007. editboxes_end:
  1008.  
  1009. ;---------------------------------------------------------------------
  1010.  
  1011. include_debug_strings
  1012.  
  1013. ;---------------------------------------------------------------------
  1014.  
  1015. type_pls        db 'URL:', 0
  1016. button_text     db 'DOWNLOAD     STOP     RESAVE', 0
  1017. download_complete db 'File saved as /rd/1/.download', 0
  1018. title           db 'HTTP Downloader', 0
  1019.  
  1020. ;---------------------------------------------------------------------
  1021. s_contentlength db 'Content-Length:'
  1022. len_contentlength = 15
  1023.  
  1024. s_chunked       db 'Transfer-Encoding: chunked'
  1025. len_chunked     = $ - s_chunked
  1026.  
  1027. string0:        db 'GET '
  1028.  
  1029. stringh                 db ' HTTP/1.1', 13, 10, 'Host: '
  1030. stringh_end:
  1031. proxy_auth_basic        db 13, 10, 'Proxy-Authorization: Basic '
  1032. proxy_auth_basic_end:
  1033. connclose               db 13, 10, 'User-Agent: Kolibrios Downloader', 13, 10, 'Connection: Close', 13, 10, 13, 10
  1034. connclose_end:
  1035.  
  1036. base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  1037.                 db '0123456789+/'
  1038.  
  1039. inifile         db '/sys/network.ini', 0
  1040.  
  1041. sec_proxy:
  1042. key_proxy       db 'proxy', 0
  1043. key_proxyport   db 'port', 0
  1044. key_user        db 'user', 0
  1045. key_password    db 'password', 0
  1046.  
  1047. sockaddr1:
  1048.                 dw AF_INET4
  1049. server_port     dw 0x5000       ; 80
  1050. server_ip       dd 0
  1051.                 rb 10
  1052.  
  1053. proxyPort       dd 80
  1054.  
  1055. shared_name     dd 0
  1056.  
  1057. ;---------------------------------------------------------------------
  1058. document_user   db 'http://', 0
  1059. ;---------------------------------------------------------------------
  1060. IM_END:
  1061. ;---------------------------------------------------------------------
  1062.                 rb URLMAXLEN-(IM_END - document_user)
  1063. ;---------------------------------------------------------------------
  1064.                 sc system_colors
  1065. ;---------------------------------------------------------------------
  1066. align 4
  1067. document        rb URLMAXLEN
  1068. ;---------------------------------------------------------------------
  1069. align 4
  1070. webAddr         rb URLMAXLEN+1
  1071. ;---------------------------------------------------------------------
  1072. pos             dd ?
  1073. socketnum       dd ?
  1074. is_chunked      dd ?
  1075. prev_chunk_end  dd ?
  1076. cur_chunk_size  dd ?
  1077. ;---------------------------------------------------------------------
  1078.  
  1079. params          rb 1024
  1080.  
  1081. request         rb 256
  1082.  
  1083. proxyAddr       rb 256
  1084. proxyUser       rb 256
  1085. proxyPassword   rb 256
  1086.  
  1087. I_END:
  1088.  
  1089.  
  1090.  
  1091.