Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 4540 → Rev 4541

/programs/develop/libraries/http/http.asm
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]
 
/programs/develop/libraries/http/http.inc
35,10 → 35,13
.buffer_length dd ? ; internal use only (number of available bytes in buffer)
.chunk_ptr dd ? ; internal use only (where the next chunk begins)
.timestamp dd ? ; internal use only (when last data was received)
 
.status dd ? ; HTTP status
.header_length dd ? ; length of HTTP header
.content_length dd ? ; length of HTTP content
.content_ptr dd ? ; ptr to content
.content_length dd ? ; total length of HTTP content
.content_received dd ? ; number of currently received content bytes
.data:
 
.http_header:
 
}
/programs/develop/libraries/http/http_en.txt
30,13 → 30,14
As long as the procedure expects more data, -1 is returned and the procedure must be called again.
- When transfer is done, the procedure will return 0.
 
All data is placed together with some flags and other attributes in the http_msg structure.
The HTTP header is placed together with some flags and other attributes in the http_msg structure.
This structure is defined in http.inc (and not copied here because it might still change.)
The identifier used by the functions is actually a pointer to this structure.
In the dword named .flags, the library will set various bit-flags indicating the status of the process.
(When a transfer is done, one should check these bit-flags to find out if the transfer was error-free.)
All received data is placed at the end of this structure, including HTTP headers.
The HTTP header is placed at the end of this structure. The content is placed in another buffer.
The dword .status contains the status code received from the server (e.g. 200 for OK).
In header_length you'll find the length of the header as soon as it has been received.
In content_length you'll find the length of the content (not counting headers).
In content_received, you'll find the number of bytes already received (not counting headers).
In content_ptr you'll find a pointer to the actual content.
In content_length you'll find the length of the content.
In content_received, you'll find the number of content bytes already received.