Subversion Repositories Kolibri OS

Rev

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