1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; HTTP library for KolibriOS ;; |
19,7 → 19,7 |
|
|
URLMAXLEN = 65535 |
BUFFERSIZE = 4096 |
BUFFERSIZE = 8192 |
TIMEOUT = 1000 ; in 1/100 s |
|
__DEBUG__ = 1 |
59,14 → 59,15 |
mov eax, buffer |
push socketnum |
popd [eax + http_msg.socket] |
lea esi, [eax + http_msg.data] |
lea esi, [eax + http_msg.http_header] |
mov [eax + http_msg.flags], FLAG_CONNECTED |
mov [eax + http_msg.write_ptr], esi |
mov [eax + http_msg.buffer_length], BUFFERSIZE - http_msg.data |
mov [eax + http_msg.buffer_length], BUFFERSIZE - http_msg.http_header |
mov [eax + http_msg.chunk_ptr], 0 |
|
mov [eax + http_msg.status], 0 |
mov [eax + http_msg.header_length], 0 |
mov [eax + http_msg.content_ptr], 0 |
mov [eax + http_msg.content_length], 0 |
mov [eax + http_msg.content_received], 0 |
|
110,16 → 111,13 |
popa |
|
DEBUGF 1, "HTTP library: init OK\n" |
|
xor eax, eax |
ret |
|
.error: |
DEBUGF 1, "ERROR loading libraries\n" |
|
xor eax, eax |
inc eax |
|
ret |
|
|
166,7 → 164,7 |
jz .error |
mov [buffer], eax |
mov edi, eax |
DEBUGF 1, "Buffer has been allocated.\n" |
DEBUGF 1, "Buffer allocated: 0x%x\n", eax |
|
mov esi, str_get |
copy_till_zero |
244,6 → 242,7 |
proc HTTP_head URL, add_header ;//////////////////////////////////////////////////////////////////;; |
;;------------------------------------------------------------------------------------------------;; |
;? Initiates a HTTP connection, using 'HEAD' method. ;; |
;? This will only return HTTP header and status, no content ;; |
;;------------------------------------------------------------------------------------------------;; |
;> URL = pointer to ASCIIZ URL ;; |
;> add_header = pointer to additional header parameters (ASCIIZ), or null for none. ;; |
357,7 → 356,8 |
;;================================================================================================;; |
proc HTTP_post URL, add_header, content_type, content_length ;////////////////////////////////////;; |
;;------------------------------------------------------------------------------------------------;; |
;? Initiates a HTTP connection, using 'GET' method. ;; |
;? Initiates a HTTP connection, using 'POST' method. ;; |
;? This method is used to send data to the HTTP server ;; |
;;------------------------------------------------------------------------------------------------;; |
;> URL = pointer to ASCIIZ URL ;; |
;> add_header = pointer to additional header parameters (ASCIIZ), or null for none. ;; |
535,11 → 535,11 |
.scan_again: |
; eax = total number of bytes received so far |
mov eax, [ebp + http_msg.write_ptr] |
sub eax, http_msg.data |
sub eax, http_msg.http_header |
sub eax, ebp |
sub eax, [ebp + http_msg.header_length] |
; edi is ptr to begin of header |
lea edi, [ebp + http_msg.data] |
lea edi, [ebp + http_msg.http_header] |
add edi, [ebp + http_msg.header_length] |
; put it in esi for next proc too |
mov esi, edi |
557,7 → 557,7 |
jmp .need_more_data |
|
.end_of_header: |
add edi, 4 - http_msg.data |
add edi, 4 - http_msg.http_header |
sub edi, ebp |
mov [ebp + http_msg.header_length], edi ; If this isnt the final header, we'll use this as an offset to find real header. |
DEBUGF 1, "Header length: %u\n", edi |
601,7 → 601,7 |
; Now, convert all header names to lowercase. |
; This way, it will be much easier to find certain header fields, later on. |
|
lea esi, [ebp + http_msg.data] |
lea esi, [ebp + http_msg.http_header] |
mov ecx, [ebp + http_msg.header_length] |
.need_newline: |
inc esi |
634,7 → 634,7 |
jmp .next_char |
.convert_done: |
mov byte[esi-1], 0 |
lea esi, [ebp + http_msg.data] |
lea esi, [ebp + http_msg.http_header] |
DEBUGF 1, "Header names converted to lowercase:\n%s\n", esi |
|
; Check for content-length header field. |
666,25 → 666,15 |
mov [ebp + http_msg.content_length], edx |
DEBUGF 1, "Content-length: %u\n", edx |
|
; Resize buffer according to content-length. |
add edx, [ebp + http_msg.header_length] |
add edx, http_msg.data |
test edx, edx |
jz .got_all_data |
|
mov ecx, edx |
sub ecx, [ebp + http_msg.write_ptr] |
mov [ebp + http_msg.buffer_length], ecx |
|
invoke mem.realloc, ebp, edx |
or eax, eax |
call alloc_contentbuff |
test eax, eax |
jz .no_ram |
xor eax, eax |
jmp .header_parsed |
|
.not_chunked: |
mov eax, [ebp + http_msg.write_ptr] |
sub eax, [ebp + http_msg.header_length] |
sub eax, http_msg.data |
sub eax, ebp |
jmp .header_parsed ; hooray! |
|
.no_content: |
DEBUGF 1, "Content-length not found.\n" |
|
692,8 → 682,17 |
; Try to find 'transfer-encoding' header. |
stdcall HTTP_find_header_field, ebp, str_te |
test eax, eax |
jz .not_chunked |
jnz .ct_hdr_found |
|
.not_chunked: |
mov edx, BUFFERSIZE |
call alloc_contentbuff |
test eax, eax |
jz .no_ram |
xor eax, eax |
jmp .header_parsed |
|
.ct_hdr_found: |
mov ebx, dword[eax] |
or ebx, 0x20202020 |
cmp ebx, 'chun' |
707,16 → 706,19 |
or [ebp + http_msg.flags], FLAG_CHUNKED |
DEBUGF 1, "Transfer type is: chunked\n" |
|
mov edx, BUFFERSIZE |
call alloc_contentbuff |
test eax, eax |
jz .no_ram |
|
; Set chunk pointer where first chunk should begin. |
lea eax, [ebp + http_msg.data] |
add eax, [ebp + http_msg.header_length] |
mov eax, [ebp + http_msg.content_ptr] |
mov [ebp + http_msg.chunk_ptr], eax |
|
.chunk_loop: |
mov ecx, [ebp + http_msg.write_ptr] |
sub ecx, [ebp + http_msg.chunk_ptr] |
jb .need_more_data_chunked ; TODO: use this ecx !!! |
|
jb .need_more_data_chunked |
; Chunkline starts here, convert the ASCII hex number into ebx |
mov esi, [ebp + http_msg.chunk_ptr] |
xor ebx, ebx |
738,47 → 740,57 |
add bl, al |
jmp .chunk_hexloop |
.chunk_: |
DEBUGF 1, "got chunk of %u bytes\n", ebx |
;; cmp esi, [ebp + http_msg.chunk_ptr] |
;; je |
; If chunk size is 0, all chunks have been received. |
test ebx, ebx |
jz .got_all_data_chunked ; last chunk, hooray! FIXME: what if it wasnt a valid hex number??? |
|
; Chunkline ends with a CR, LF or simply LF |
dec esi |
.end_of_chunkline?: |
lodsb |
cmp al, 10 |
je .end_of_chunkline |
lodsb |
cmp edi, [ebp + http_msg.write_ptr] |
cmp esi, [ebp + http_msg.write_ptr] |
jb .end_of_chunkline? |
jmp .need_more_data |
|
.end_of_chunkline: |
; Update chunk ptr, and remember old one |
mov edi, [ebp + http_msg.chunk_ptr] |
add [ebp + http_msg.chunk_ptr], ebx |
DEBUGF 1, "Chunk of %u bytes\n", ebx |
; If chunk size is 0, all chunks have been received. |
test ebx, ebx |
jz .got_all_data_chunked |
; Calculate how many data bytes we'll need to shift |
mov ecx, [ebp + http_msg.write_ptr] |
sub ecx, [ebp + http_msg.chunk_ptr] |
; Calculate how many bytes we'll need to shift them |
sub esi, [ebp + http_msg.chunk_ptr] |
; Update write ptr |
sub [ebp + http_msg.write_ptr], esi |
; Realloc buffer, make it 'chunksize' bigger. |
mov eax, [ebp + http_msg.buffer_length] |
add eax, ebx |
invoke mem.realloc, ebp, eax |
add ebx, [ebp + http_msg.chunk_ptr] |
sub ebx, [ebp + http_msg.content_ptr] |
add ebx, BUFFERSIZE ; add some space for new chunkline header |
DEBUGF 1, "Resizing buffer 0x%x, it will now be %u bytes\n", [ebp + http_msg.content_ptr], ebx |
invoke mem.realloc, [ebp + http_msg.content_ptr], ebx |
DEBUGF 1, "New buffer = 0x%x\n", eax |
or eax, eax |
jz .no_ram |
add [ebp + http_msg.buffer_length], ebx |
|
; Update write ptr |
mov eax, esi |
sub eax, edi |
sub [ebp + http_msg.write_ptr], eax |
|
; Now move all received data to the left (remove chunk header). |
; Update content_length accordingly. |
mov ecx, [ebp + http_msg.write_ptr] |
sub ecx, esi |
call recalculate_pointers |
; Calculate remaining available buffer size |
mov eax, [ebp + http_msg.content_ptr] |
add eax, ebx |
sub eax, [ebp + http_msg.write_ptr] |
mov [ebp + http_msg.buffer_length], eax |
; Move all received data to the left (remove chunk header). |
mov edi, [ebp + http_msg.chunk_ptr] |
add esi, edi |
; Update chunk ptr so it points to next chunk |
sub ebx, BUFFERSIZE |
add [ebp + http_msg.chunk_ptr], ebx |
; Update number of received content bytes |
add [ebp + http_msg.content_received], ecx |
DEBUGF 1, "Moving %u bytes from 0x%x to 0x%x\n", ecx, esi, edi |
rep movsb |
|
xor eax, eax |
jmp .chunk_loop |
|
;--------------------------------------------------------- |
; Check if we got all the data. |
.header_parsed: |
add [ebp + http_msg.content_received], eax |
790,12 → 802,15 |
jmp .need_more_data |
|
.need_more_data_and_space: |
test [ebp + http_msg.flags], FLAG_GOT_HEADER |
jz .invalid_header ; It's just too damn long! |
mov eax, [ebp + http_msg.write_ptr] |
add eax, BUFFERSIZE |
sub eax, ebp |
invoke mem.realloc, ebp, eax |
sub eax, [ebp + http_msg.content_ptr] |
invoke mem.realloc, [ebp + http_msg.content_ptr], eax |
or eax, eax |
jz .no_ram |
call recalculate_pointers |
mov [ebp + http_msg.buffer_length], BUFFERSIZE |
|
.need_more_data: |
813,9 → 828,7 |
|
.got_all_data_chunked: |
mov eax, [ebp + http_msg.chunk_ptr] |
sub eax, [ebp + http_msg.header_length] |
sub eax, http_msg.data |
sub eax, ebp |
sub eax, [ebp + http_msg.content_ptr] |
mov [ebp + http_msg.content_length], eax |
mov [ebp + http_msg.content_received], eax |
.got_all_data: |
834,7 → 847,7 |
mcall 29, 9 |
sub eax, TIMEOUT |
cmp eax, [ebp + http_msg.timestamp] |
jb .need_more_data |
jl .need_more_data |
DEBUGF 1, "ERROR: timeout\n" |
or [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR |
jmp .disconnect |
877,8 → 890,57 |
endp |
|
|
alloc_contentbuff: |
|
; Allocate content buffer |
invoke mem.alloc, edx |
or eax, eax |
jz .no_ram |
|
DEBUGF 1, "Content buffer allocated: 0x%x\n", eax |
|
; Copy already received content into content buffer |
mov edi, eax |
lea esi, [ebp + http_msg.http_header] |
add esi, [ebp + http_msg.header_length] |
mov ecx, [ebp + http_msg.write_ptr] |
sub ecx, esi |
mov ebx, ecx |
rep movsb |
|
; Update pointers to point to new buffer |
mov [ebp + http_msg.content_ptr], eax |
mov [ebp + http_msg.content_received], ebx |
sub edx, ebx |
mov [ebp + http_msg.buffer_length], edx |
add eax, ebx |
mov [ebp + http_msg.write_ptr], eax |
|
; Shrink header buffer |
mov eax, http_msg.http_header |
add eax, [ebp + http_msg.header_length] |
invoke mem.realloc, ebp, eax |
or eax, eax |
.no_ram: |
|
ret |
|
|
|
recalculate_pointers: |
|
sub eax, [ebp + http_msg.content_ptr] |
jz .done |
add [ebp + http_msg.content_ptr], eax |
add [ebp + http_msg.write_ptr], eax |
add [ebp + http_msg.chunk_ptr], eax |
|
.done: |
ret |
|
|
|
|
;;================================================================================================;; |
proc HTTP_free identifier ;///////////////////////////////////////////////////////////////////////;; |
;;------------------------------------------------------------------------------------------------;; |
888,7 → 950,7 |
;;------------------------------------------------------------------------------------------------;; |
;< none ;; |
;;================================================================================================;; |
|
DEBUGF 1, "HTTP_free: 0x%x\n", [identifier] |
pusha |
mov ebp, [identifier] |
|
949,7 → 1011,7 |
test [ebx + http_msg.flags], FLAG_GOT_HEADER |
jz .fail |
|
lea edx, [ebx + http_msg.data] |
lea edx, [ebx + http_msg.http_header] |
mov ecx, edx |
add ecx, [ebx + http_msg.header_length] |
|