Extended http library API to allow keepalive connections, streaming connections and transfer of large files.

git-svn-id: svn://kolibrios.org@5534 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2015-03-20 12:04:14 +00:00
parent 5080442b18
commit d52d41e20d
9 changed files with 242 additions and 111 deletions

View File

@ -220,7 +220,7 @@ void main()
case evNetwork:
if (http_transfer > 0) {
http_process stdcall (http_transfer);
http_receive stdcall (http_transfer);
$push EAX
ESI = http_transfer;
wv_progress_bar.max = ESI.http_msg.content_length;
@ -618,7 +618,7 @@ void OpenPage()
if (strncmp(#URL,"http:",5)==0)
{
img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-2, 17, skin.h, 131, 0);
http_get stdcall (#URL, #accept_language);
http_get stdcall (#URL, 0, 0, #accept_language);
http_transfer = EAX;
if (http_transfer == 0)
{

View File

@ -88,7 +88,7 @@ void Downloader()
default:
if (DL_Form.width==0) || (DL_http_transfer <= 0) break;
http_process stdcall (DL_http_transfer);
http_receive stdcall (DL_http_transfer);
$push EAX
ESI = DL_http_transfer;
DL_progress_bar.max = ESI.http_msg.content_length;
@ -220,7 +220,7 @@ void StartDownloading()
{
download_state = STATE_IN_PROGRESS;
DL_address_box.color = DL_address_box.blur_border_color = DL_address_box.focus_border_color = 0xdddDDD;
http_get stdcall (#DL_URL, #accept_language);
http_get stdcall (#DL_URL, 0, 0, #accept_language);
DL_http_transfer = EAX;
DL_progress_bar.value = 0;
DL_Draw_Window();

View File

@ -96,7 +96,7 @@ void main()
default:
if (Form.width==0) break;
if (http_transfer <= 0) break;
http_process stdcall (http_transfer);
http_receive stdcall (http_transfer);
if (EAX == 0) {
ESI = http_transfer;
bufpointer = ESI.http_msg.content_ptr;
@ -222,7 +222,7 @@ void StartDownloading()
if (strncmp(#URL,"http:",5)==0)
{
address_box.color = address_box.blur_border_color = address_box.focus_border_color = 0xededed;
http_get stdcall (#URL, #accept_language);
http_get stdcall (#URL, 0, 0, #accept_language);
http_transfer = EAX;
Draw_Window();
if (http_transfer == 0)

View File

@ -8,9 +8,10 @@ dword http_get = #aHTTPget;
dword http_head = #aHTTPhead;
dword http_post = #aHTTPpost;
dword http_find_header_field = #aFHF;
dword http_process = #aHTTPprocess;
dword http_send = #aHTTPsend;
dword http_receive = #aHTTPreceive;
dword http_disconnect = #aHTTPdisconnect;
dword http_free = #aHTTPfree;
dword http_stop = #aHTTPstop;
dword uri_escape = #aURIescape;
dword uri_unescape = #aURIunescape;
$DD 2 dup 0
@ -20,12 +21,14 @@ char aHTTPget[4] = "get\0";
char aHTTPhead[5] = "head\0";
char aHTTPpost[5] = "post\0";
char aFHF[18] = "find_header_field\0";
char aHTTPprocess[8] = "process\0";
char aHTTPsend[5] = "send\0";
char aHTTPreceive[8] = "receive\0";
char aHTTPdisconnect[11] = "disconnect\0";
char aHTTPfree[5] = "free\0";
char aHTTPstop[5] = "stop\0";
char aURIescape[7] = "escape\0";
char aURIunescape[9] = "unescape\0";
// status flags
#define FLAG_HTTP11 1 << 0
#define FLAG_GOT_HEADER 1 << 1
#define FLAG_GOT_ALL_DATA 1 << 2
@ -33,7 +36,11 @@ char aURIunescape[9] = "unescape\0";
#define FLAG_CHUNKED 1 << 4
#define FLAG_CONNECTED 1 << 5
// error flags go into the upper word
// user flags
#define FLAG_KEEPALIVE 1 << 8
#define FLAG_MULTIBUFF 1 << 9
// error flags
#define FLAG_INVALID_HEADER 1 << 16
#define FLAG_NO_RAM 1 << 17
#define FLAG_SOCKET_ERROR 1 << 18

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2009-2013. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2009-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; downloader.asm - HTTP client for KolibriOS ;;
@ -168,13 +168,13 @@ fail:
download_1:
DEBUGF 1, "Starting download\n"
invoke HTTP_get, params, 0
invoke HTTP_get, 0, 0, params, 0
test eax, eax
jz fail
mov [identifier], eax
.loop:
invoke HTTP_process, [identifier]
invoke HTTP_receive, [identifier]
test eax, eax
jnz .loop
ret
@ -284,7 +284,7 @@ library lib_http, 'http.obj', \
import lib_http, \
HTTP_get , 'get', \
HTTP_process , 'process' ,\
HTTP_receive , 'receive', \
HTTP_free , 'free'
import box_lib, \

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2014. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2014-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; pasta.asm - Paste something to paste.kolibrios.org using POST ;;
@ -42,13 +42,13 @@ START:
test eax, eax
jnz exit
invoke HTTP_get, sz_url, 0
invoke HTTP_get, sz_url, 0, 0, 0
test eax, eax
jz error
mov [identifier], eax
.again:
invoke HTTP_process, [identifier]
invoke HTTP_receive, [identifier]
test eax, eax
jnz .again
@ -78,7 +78,7 @@ START:
invoke HTTP_free, [identifier]
invoke HTTP_post, sz_url, sz_cookie, sz_ctype, sz_paste.length
invoke HTTP_post, sz_url, 0, 0, sz_cookie, sz_ctype, sz_paste.length
test eax, eax
jz error
mov [identifier], eax
@ -87,7 +87,7 @@ START:
mcall 75, 6, , sz_paste, sz_paste.length, 0
.again2:
invoke HTTP_process, [identifier]
invoke HTTP_receive, [identifier]
test eax, eax
jnz .again2
@ -142,11 +142,10 @@ library lib_http, 'http.obj'
import lib_http, \
HTTP_get, 'get', \
HTTP_process, 'process', \
HTTP_free, 'free', \
HTTP_stop, 'stop', \
HTTP_post, 'post', \
HTTP_find_header_field, 'find_header_field'
HTTP_receive, 'receive', \
HTTP_find_header_field, 'find_header_field', \
HTTP_free, 'free'
identifier dd 0

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; HTTP library for KolibriOS ;;
@ -54,13 +54,15 @@ local .copyloop, .copydone
.copydone:
}
macro HTTP_init_buffer buffer, socketnum {
macro HTTP_init_buffer buffer, socketnum, flags {
mov eax, buffer
push socketnum
popd [eax + http_msg.socket]
lea esi, [eax + http_msg.http_header]
mov [eax + http_msg.flags], FLAG_CONNECTED
push flags
pop [eax + http_msg.flags]
or [eax + http_msg.flags], FLAG_CONNECTED
mov [eax + http_msg.write_ptr], esi
mov [eax + http_msg.buffer_length], BUFFERSIZE - http_msg.http_header
mov [eax + http_msg.chunk_ptr], 0
@ -176,25 +178,30 @@ proc HTTP_free identifier ;/////////////////////////////////////////////////////
endp
;;================================================================================================;;
proc HTTP_get URL, add_header ;///////////////////////////////////////////////////////////////////;;
proc HTTP_get URL, identifier, flags, add_header ;////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? Initiates a HTTP connection, using 'GET' method. ;;
;;------------------------------------------------------------------------------------------------;;
;> URL = pointer to ASCIIZ URL ;;
;> add_header = pointer to additional header parameters (ASCIIZ), or null for none. ;;
;> identifier = Identifier of an already open connection, or NULL to create a new one. ;;
;> flags = Flags indicating how to threat the connection. ;;
;> add_header = pointer to additional header parameters (ASCIIZ), or NULL for none. ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) / buffer ptr ;;
;;================================================================================================;;
locals
hostname dd ?
pageaddr dd ?
sockaddr dd ?
socketnum dd ?
buffer dd ?
port dd ?
endl
and [flags], FLAG_KEEPALIVE or FLAG_MULTIBUFF ; filter out invalid flags
pusha
; split the URL into hostname and pageaddr
@ -205,13 +212,24 @@ endl
mov [pageaddr], ebx
mov [port], ecx
mov eax, [identifier]
test eax, eax
jz .open_new
test [eax + http_msg.flags], FLAG_CONNECTED
jz .error
mov eax, [eax + http_msg.socket]
mov [socketnum], eax
jmp .send_request
; Connect to the other side.
.open_new:
stdcall open_connection, [hostname], [port]
test eax, eax
jz .error
mov [socketnum], eax
; Create the HTTP request.
.send_request:
invoke mem.alloc, BUFFERSIZE
test eax, eax
jz .error
@ -256,6 +274,11 @@ endl
mov esi, str_close
mov ecx, str_close.length
test [flags], FLAG_KEEPALIVE
jz @f
mov esi, str_keep
mov ecx, str_keep.length
@@:
rep movsb
mov byte[edi], 0
@ -275,12 +298,20 @@ endl
jz .error
DEBUGF 1, "Request has been sent to server.\n"
HTTP_init_buffer [buffer], [socketnum]
cmp [identifier], 0
jne .old_connection
HTTP_init_buffer [buffer], [socketnum], [flags]
popa
mov eax, [buffer] ; return buffer ptr
ret
.old_connection:
invoke mem.free, [buffer]
popa
mov eax, [identifier]
ret
.error:
DEBUGF 1, "Error!\n"
popa
@ -292,25 +323,28 @@ endp
;;================================================================================================;;
proc HTTP_head URL, add_header ;//////////////////////////////////////////////////////////////////;;
proc HTTP_head URL, identifier, flags, 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. ;;
;> identifier = Identifier of an already open connection, or NULL to create a new one. ;;
;> flags = Flags indicating how to threat the connection. ;;
;> add_header = pointer to additional header parameters (ASCIIZ), or NULL for none. ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) / buffer ptr ;;
;;================================================================================================;;
locals
hostname dd ?
pageaddr dd ?
sockaddr dd ?
socketnum dd ?
buffer dd ?
port dd ?
endl
and [flags], FLAG_KEEPALIVE or FLAG_MULTIBUFF ; filter out invalid flags
pusha
; split the URL into hostname and pageaddr
stdcall parse_url, [URL]
@ -320,13 +354,24 @@ endl
mov [pageaddr], ebx
mov [port], ecx
mov eax, [identifier]
test eax, eax
jz .open_new
test [eax + http_msg.flags], FLAG_CONNECTED
jz .error
mov eax, [eax + http_msg.socket]
mov [socketnum], eax
jmp .send_request
; Connect to the other side.
.open_new:
stdcall open_connection, [hostname], [port]
test eax, eax
jz .error
mov [socketnum], eax
; Create the HTTP request.
.send_request:
invoke mem.alloc, BUFFERSIZE
test eax, eax
jz .error
@ -371,12 +416,16 @@ endl
mov esi, str_close
mov ecx, str_close.length
test [flags], FLAG_KEEPALIVE
jz @f
mov esi, str_keep
mov ecx, str_keep.length
@@:
rep movsb
mov byte[edi], 0
DEBUGF 1, "Request:\n%s", [buffer]
; Free unused memory
push edi
invoke mem.free, [pageaddr]
@ -391,11 +440,19 @@ endl
jz .error
DEBUGF 1, "Request has been sent to server.\n"
HTTP_init_buffer [buffer], [socketnum]
cmp [identifier], 0
jne .old_connection
HTTP_init_buffer [buffer], [socketnum], [flags]
popa
mov eax, [buffer]
ret ; return buffer ptr
mov eax, [buffer] ; return buffer ptr
ret
.old_connection:
invoke mem.free, [buffer]
popa
mov eax, [identifier]
ret
.error:
DEBUGF 1, "Error!\n"
@ -407,27 +464,30 @@ endp
;;================================================================================================;;
proc HTTP_post URL, add_header, content_type, content_length ;////////////////////////////////////;;
proc HTTP_post URL, identifier, flags, add_header, content_type, content_length ;/////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? 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. ;;
;> identifier = Identifier of an already open connection, or NULL to create a new one. ;;
;> flags = Flags indicating how to threat the connection. ;;
;> add_header = pointer to additional header parameters (ASCIIZ), or NULL for none. ;;
;> content_type = pointer to ASCIIZ string containing content type ;;
;> content_length = length of content (in bytes) ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) / buffer ptr ;;
;< eax = 0 (error) / buffer ptr (aka Identifier) ;;
;;================================================================================================;;
locals
hostname dd ?
pageaddr dd ?
sockaddr dd ?
socketnum dd ?
buffer dd ?
port dd ?
endl
and [flags], FLAG_KEEPALIVE or FLAG_MULTIBUFF ; filter out invalid flags
pusha
; split the URL into hostname and pageaddr
stdcall parse_url, [URL]
@ -437,13 +497,24 @@ endl
mov [pageaddr], ebx
mov [port], ecx
mov eax, [identifier]
test eax, eax
jz .open_new
test [eax + http_msg.flags], FLAG_CONNECTED
jz .error
mov eax, [eax + http_msg.socket]
mov [socketnum], eax
jmp .send_request
; Connect to the other side.
.open_new:
stdcall open_connection, [hostname], [port]
test eax, eax
jz .error
mov [socketnum], eax
; Create the HTTP request.
.send_request:
invoke mem.alloc, BUFFERSIZE
test eax, eax
jz .error
@ -502,6 +573,11 @@ endl
mov esi, str_close
mov ecx, str_close.length
test [flags], FLAG_KEEPALIVE
jz @f
mov esi, str_keep
mov ecx, str_keep.length
@@:
rep movsb
mov byte[edi], 0
@ -521,11 +597,22 @@ endl
jz .error
DEBUGF 1, "Request has been sent to server.\n"
HTTP_init_buffer [buffer], [socketnum]
cmp [identifier], 0
jne .old_connection
HTTP_init_buffer [buffer], [socketnum], [flags]
popa
mov eax, [buffer]
ret ; return buffer ptr
mov eax, [buffer] ; return buffer ptr
ret
.old_connection:
invoke mem.free, [buffer]
mov ebx, [flags]
mov eax, [identifier]
or [eax + http_msg.flags], ebx
popa
mov eax, [identifier]
ret
.error:
DEBUGF 1, "Error!\n"
@ -555,7 +642,22 @@ proc HTTP_receive identifier ;//////////////////////////////////////////////////
test [ebp + http_msg.flags], FLAG_CONNECTED
jz .connection_closed
; If the buffer is full, allocate a new one
cmp [ebp + http_msg.buffer_length], 0
jne .receive
test [ebp + http_msg.flags], FLAG_MULTIBUFF
jz .err_header
invoke mem.alloc, BUFFERSIZE
test eax, eax
jz .err_no_ram
mov [ebp + http_msg.content_ptr], eax
mov [ebp + http_msg.write_ptr], eax
mov [ebp + http_msg.buffer_length], BUFFERSIZE
; Receive some data
.receive:
mcall recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
[ebp + http_msg.buffer_length], MSG_DONTWAIT
cmp eax, 0xffffffff
@ -841,6 +943,8 @@ proc HTTP_receive identifier ;//////////////////////////////////////////////////
mov edx, esi
sub edx, [ebp + http_msg.chunk_ptr] ; edx is now length of chunkline
sub [ebp + http_msg.write_ptr], edx
test [ebp + http_msg.flags], FLAG_MULTIBUFF
jnz .dont_resize
; Realloc buffer, make it 'chunksize' bigger.
lea edx, [ebx + BUFFERSIZE]
mov [ebp + http_msg.buffer_length], edx ; remaining space in new buffer
@ -853,6 +957,7 @@ proc HTTP_receive identifier ;//////////////////////////////////////////////////
jz .err_no_ram
call recalculate_pointers ; Because it's possible that buffer begins on another address now
add esi, eax ; recalculate esi too!
.dont_resize:
; Remove chunk header (aka chunkline) from the buffer by shifting all received data after chunkt_ptr to the left
mov edi, [ebp + http_msg.chunk_ptr]
rep movsb
@ -887,7 +992,8 @@ proc HTTP_receive identifier ;//////////////////////////////////////////////////
ret
.buffer_full:
; Lets make it bigger..
test [ebp + http_msg.flags], FLAG_MULTIBUFF
jnz .multibuff
mov eax, [ebp + http_msg.write_ptr]
add eax, BUFFERSIZE
sub eax, [ebp + http_msg.content_ptr]
@ -902,6 +1008,12 @@ proc HTTP_receive identifier ;//////////////////////////////////////////////////
dec eax
ret
.multibuff:
; This buffer is full
popa
xor eax, eax
ret
.need_more_data_for_header:
cmp [ebp + http_msg.buffer_length], 0
je .err_header ; It's just too damn long!
@ -1151,24 +1263,22 @@ endp
;;================================================================================================;;
proc HTTP_escape URI ;////////////////////////////////////////////////////////////////////////////;;
proc HTTP_escape URI, length ;////////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? ;;
;;------------------------------------------------------------------------------------------------;;
;> URI = ptr to ASCIIZ URI ;;
;> URI = ptr to ASCIIZ URI/data ;;
;> length = length of URI/data ;;
;;------------------------------------------------------------------------------------------------;;
;< eax = 0 (error) / ptr to ASCIIZ URI/data ;;
;< ebx = length of escaped URI/data ;;
;;================================================================================================;;
; TODO: instead of static buffer allocation, make it 4096 bytes and larger only if needed
DEBUGF 1, "HTTP_escape: %s\n", [URI]
pusha
invoke mem.alloc, URLMAXLEN
invoke mem.alloc, URLMAXLEN ; FIXME: use length provided by caller to guess final size.
test eax, eax
jz .error
mov [esp + 7 * 4], eax ; return ptr in eax
@ -1227,7 +1337,7 @@ endp
;;================================================================================================;;
proc HTTP_unescape URI ;//////////////////////////////////////////////////////////////////////////;;
proc HTTP_unescape URI, length ;//////////////////////////////////////////////////////////////////;;
;;------------------------------------------------------------------------------------------------;;
;? ;;
;;------------------------------------------------------------------------------------------------;;
@ -1239,7 +1349,7 @@ proc HTTP_unescape URI ;////////////////////////////////////////////////////////
DEBUGF 1, "HTTP_unescape: %s\n", [URI]
pusha
invoke mem.alloc, URLMAXLEN
invoke mem.alloc, URLMAXLEN ; FIXME: use length provided by caller
test eax, eax
jz .error
mov [esp + 7 * 4], eax ; return ptr in eax
@ -1768,7 +1878,9 @@ str_post_ct db 13, 10, 'Content-Type: '
.length = $ - str_post_ct
str_proxy_auth db 13, 10, 'Proxy-Authorization: Basic '
.length = $ - str_proxy_auth
str_close db 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
str_close db 'User-Agent: KolibriOS libHTTP/1.1', 13, 10, 'Connection: Close', 13, 10, 13, 10
.length = $ - str_close
str_keep db 'User-Agent: KolibriOS libHTTP/1.1', 13, 10, 'Connection: Keepalive', 13, 10, 13, 10
.length = $ - str_close
str_http db 'http://', 0

View File

@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; HTTP library for KolibriOS ;;
@ -14,13 +14,20 @@
; Bitflags for http_msg.flags
; status
FLAG_HTTP11 = 1 shl 0
FLAG_GOT_HEADER = 1 shl 1
FLAG_GOT_ALL_DATA = 1 shl 2
FLAG_CONTENT_LENGTH = 1 shl 3
FLAG_CHUNKED = 1 shl 4
FLAG_CONNECTED = 1 shl 5
; ERROR flags go into the upper word
; user options
FLAG_KEEPALIVE = 1 shl 8
FLAG_MULTIBUFF = 1 shl 9
; error
FLAG_INVALID_HEADER = 1 shl 16
FLAG_NO_RAM = 1 shl 17
FLAG_SOCKET_ERROR = 1 shl 18

View File

@ -1,20 +1,26 @@
get(*url, *add_header);
get(*url, identifier, flags, *add_header);
*url = pointer to ASCIIZ URL
identifier = identified of previously opened connection, or 0 to open a new one
flags = bit flags (see http.inc user flags)
*add_header = pointer to ASCIIZ additional header parameters, or null for none.
Every additional parameter must end with CR LF bytes, including the last line.
Initiates a HTTP connection, using 'GET' method.
- returns 0 on error, identifier otherwise.
head(*url, *add_header);
head(*url, identifier, flags, *add_header);
*url = pointer to ASCIIZ URL
identifier = identified of previously opened connection, or 0 to open a new one
flags = bit flags (see http.inc user flags)
*add_header = pointer to ASCIIZ additional header parameters, or null for none.
Every additional parameter must end with CR LF bytes, including the last line.
Initiate a HTTP connection, using 'HEAD' method.
- returns 0 on error, identifier otherwise
post(*url, *add_header, *content-type, content-length);
post(*url, identifier, flags, *add_header, *content-type, content-length);
*url = pointer to ASCIIZ URL
identifier = identified of previously opened connection, or 0 to open a new one
flags = bit flags (see http.inc user flags)
*add_header = pointer to ASCIIZ additional header parameters, or null for none.
Every additional parameter must end with CR LF bytes, including the last line.
*content-type = pointer to ASCIIZ string containing content type.