Subversion Repositories Kolibri OS

Rev

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