From 44992ba6dfd67120126e148142adfad0c3f153e8 Mon Sep 17 00:00:00 2001 From: hidnplayr Date: Tue, 5 Nov 2013 11:22:31 +0000 Subject: [PATCH] HTTP lib: added support for HEAD and POST methods git-svn-id: svn://kolibrios.org@4167 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/libraries/http/http.asm | 381 +++++++++++++++++++---- 1 file changed, 326 insertions(+), 55 deletions(-) diff --git a/programs/develop/libraries/http/http.asm b/programs/develop/libraries/http/http.asm index 12fe95f227..7d500ce232 100644 --- a/programs/develop/libraries/http/http.asm +++ b/programs/develop/libraries/http/http.asm @@ -51,6 +51,22 @@ macro copy_till_zero { @@: } +macro HTTP_init_buffer buffer, socketnum { + + mov eax, buffer + push socketnum + popd [eax + http_msg.socket] + lea esi, [eax + http_msg.data] + mov [eax + http_msg.flags], 0 + mov [eax + http_msg.write_ptr], esi + mov [eax + http_msg.buffer_length], BUFFERSIZE - http_msg.data + 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_length], 0 +} + section '.flat' code readable align 16 ;;===========================================================================;; @@ -108,6 +124,7 @@ locals sockaddr dd ? socketnum dd ? buffer dd ? + port dd ? endl ; split the URL into hostname and pageaddr @@ -121,59 +138,29 @@ endl cmp [proxyAddr], 0 jne .proxy_done - ; TODO .proxy_done: -; Resolve the hostname - DEBUGF 1, "Resolving hostname\n" - push esp ; reserve stack place - push esp ; fourth parameter - push 0 ; third parameter - push 0 ; second parameter - push [hostname] - call [getaddrinfo] - pop esi - test eax, eax - jnz .error +;;;; + mov [port], 80 ;;;; FIXME -; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct - mov esi, [esi + addrinfo.ai_addr] - mov [sockaddr], esi - mov eax, [esi + sockaddr_in.sin_addr] - test eax, eax - jz .error - - DEBUGF 1, "Server ip=%u.%u.%u.%u\n", \ - [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \ - [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1 - - mov [esi + sockaddr_in.sin_family], AF_INET4 - mov [esi + sockaddr_in.sin_port], 80 shl 8 ;;; FIXME - -; Connect to the server. - mcall socket, AF_INET4, SOCK_STREAM, 0 +; Connect to the other side. + stdcall open_connection, [hostname], [port] test eax, eax jz .error mov [socketnum], eax - DEBUGF 1, "Socket: 0x%x\n", eax - - mcall connect, [socketnum], [sockaddr], 18 - test eax, eax - jnz .error - DEBUGF 1, "Socket is now connected.\n" - - ; TODO: free address buffer(s) ; Create the HTTP request. invoke mem.alloc, BUFFERSIZE test eax, eax jz .error mov [buffer], eax + mov edi, eax DEBUGF 1, "Buffer has been allocated.\n" - mov dword[eax], 'GET ' - lea edi, [eax + 4] - mov esi, [pageaddr] ; TODO: for proxy use http:// and then full URL + mov esi, str_get + copy_till_zero + + mov esi, [pageaddr] copy_till_zero mov esi, str_http11 @@ -190,7 +177,7 @@ endl mov byte[edi], 0 DEBUGF 1, "Request:\n%s", [buffer] -; now send the request +; Send the request mov esi, edi sub esi, [buffer] ; length xor edi, edi ; flags @@ -200,19 +187,209 @@ endl jz .error DEBUGF 1, "Request has been sent to server.\n" -; Now that we have sent the request, re-purpose buffer as receive buffer - mov eax, [buffer] - push [socketnum] - popd [eax + http_msg.socket] - lea esi, [eax + http_msg.data] - mov [eax + http_msg.flags], 0 - mov [eax + http_msg.write_ptr], esi - mov [eax + http_msg.buffer_length], BUFFERSIZE - http_msg.data - mov [eax + http_msg.chunk_ptr], 0 + HTTP_init_buffer [buffer], [socketnum] - mov [eax + http_msg.status], 0 - mov [eax + http_msg.header_length], 0 - mov [eax + http_msg.content_length], 0 + ret ; return buffer ptr + + .error: + DEBUGF 1, "Error!\n" + xor eax, eax ; return 0 = error + ret + +endp + + + +;;================================================================================================;; +proc HTTP_head URL ;///////////////////////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? ;; +;;------------------------------------------------------------------------------------------------;; +;> _ ;; +;;------------------------------------------------------------------------------------------------;; +;< eax = 0 (error) / buffer ptr ;; +;;================================================================================================;; +locals + hostname dd ? + pageaddr dd ? + sockaddr dd ? + socketnum dd ? + buffer dd ? + port dd ? +endl + +; split the URL into hostname and pageaddr + stdcall parse_url, [URL] + test eax, eax + jz .error + mov [hostname], eax + mov [pageaddr], ebx + +; Do we need to use a proxy? + cmp [proxyAddr], 0 + jne .proxy_done + + ; TODO: set hostname to that of the + .proxy_done: + +;;;; + mov [port], 80 ;;;; FIXME + +; Connect to the other side. + stdcall open_connection, [hostname], [port] + test eax, eax + jz .error + mov [socketnum], eax + +; Create the HTTP request. + invoke mem.alloc, BUFFERSIZE + test eax, eax + jz .error + mov [buffer], eax + mov edi, eax + DEBUGF 1, "Buffer has been allocated.\n" + + mov esi, str_head + copy_till_zero + + mov esi, [pageaddr] + copy_till_zero + + mov esi, str_http11 + mov ecx, str_http11.length + rep movsb + + mov esi, [hostname] + copy_till_zero + + mov esi, str_close + mov ecx, str_close.length + rep movsb + + mov byte[edi], 0 + DEBUGF 1, "Request:\n%s", [buffer] + +; Send the request + mov esi, edi + sub esi, [buffer] ; length + xor edi, edi ; flags + + mcall send, [socketnum], [buffer] + test eax, eax + jz .error + DEBUGF 1, "Request has been sent to server.\n" + + HTTP_init_buffer [buffer], [socketnum] + + ret ; return buffer ptr + + .error: + DEBUGF 1, "Error!\n" + xor eax, eax ; return 0 = error + ret + +endp + + +;;================================================================================================;; +proc HTTP_post URL, content, content_type, content_length ;///////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? ;; +;;------------------------------------------------------------------------------------------------;; +;> _ ;; +;;------------------------------------------------------------------------------------------------;; +;< eax = 0 (error) / buffer ptr ;; +;;================================================================================================;; +locals + hostname dd ? + pageaddr dd ? + sockaddr dd ? + socketnum dd ? + buffer dd ? + port dd ? +endl + +; split the URL into hostname and pageaddr + stdcall parse_url, [URL] + test eax, eax + jz .error + mov [hostname], eax + mov [pageaddr], ebx + +; Do we need to use a proxy? + cmp [proxyAddr], 0 + jne .proxy_done + + ; TODO: set hostname to that of the + .proxy_done: + +;;;; + mov [port], 80 ;;;; FIXME + +; Connect to the other side. + stdcall open_connection, [hostname], [port] + test eax, eax + jz .error + mov [socketnum], eax + +; Create the HTTP request. + invoke mem.alloc, BUFFERSIZE + test eax, eax + jz .error + mov [buffer], eax + mov edi, eax + DEBUGF 1, "Buffer has been allocated.\n" + + mov esi, str_post + copy_till_zero + + mov esi, [pageaddr] + copy_till_zero + + mov esi, str_http11 + mov ecx, str_http11.length + rep movsb + + mov esi, [hostname] + copy_till_zero + + mov esi, str_post_cl + mov ecx, str_post_cl.length + rep movsb + + mov eax, [content_length] + call ascii_dec + + mov esi, str_post_ct + mov ecx, str_post_ct.length + rep movsb + + mov esi, [content_type] + rep movsb + + mov esi, str_close + mov ecx, str_close.length + rep movsb + + mov byte[edi], 0 + DEBUGF 1, "Request:\n%s", [buffer] + +; Send the request + mov esi, edi + sub esi, [buffer] ; length + xor edi, edi ; flags + mcall send, [socketnum], [buffer] + test eax, eax + jz .error + DEBUGF 1, "Request has been sent to server.\n" + + mcall send, [socketnum], [content], [content_length] + test eax, eax + jz .error + DEBUGF 1, "Data has been sent to server.\n" + + HTTP_init_buffer [buffer], [socketnum] +; mov eax, [buffer] ret ; return buffer ptr @@ -505,7 +682,6 @@ proc HTTP_process identifier ;////////////////////////////////////////////////// sub eax, http_msg.data sub eax, ebp mov [ebp + http_msg.content_length], eax - .got_all_data: DEBUGF 1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_length] or [ebp + http_msg.flags], FLAG_GOT_DATA @@ -611,6 +787,80 @@ endp ; internal procedures start here: +;;================================================================================================;; +proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;; +;;------------------------------------------------------------------------------------------------;; +;? ;; +;;------------------------------------------------------------------------------------------------;; +;> _ ;; +;;------------------------------------------------------------------------------------------------;; +;< eax = -1 (error) / 0 ;; +;;================================================================================================;; + +locals + sockaddr dd ? + socketnum dd ? +endl + +; Resolve the hostname + DEBUGF 1, "Resolving hostname\n" + push esp ; reserve stack place + push esp ; fourth parameter + push 0 ; third parameter + push 0 ; second parameter + push [hostname] + call [getaddrinfo] + pop esi + test eax, eax + jnz .error1 + +; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct + mov esi, [esi + addrinfo.ai_addr] + mov [sockaddr], esi + mov eax, [esi + sockaddr_in.sin_addr] + test eax, eax + jz .error2 + + DEBUGF 1, "Server ip=%u.%u.%u.%u\n", \ + [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \ + [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1 + + mov [esi + sockaddr_in.sin_family], AF_INET4 + mov eax, [port] + xchg al, ah + mov [esi + sockaddr_in.sin_port], ax + +; Connect to the server. + mcall socket, AF_INET4, SOCK_STREAM, 0 + test eax, eax + jz .error2 + mov [socketnum], eax + DEBUGF 1, "Socket: 0x%x\n", eax + + mcall connect, [socketnum], [sockaddr], 18 + test eax, eax + jnz .error2 + DEBUGF 1, "Socket is now connected.\n" + +; free allocated memory + push [sockaddr] + call [freeaddrinfo] + + mov eax, [socketnum] + ret + + .error2: + +; free allocated memory + push [sockaddr] + call [freeaddrinfo] + + .error1: + xor eax, eax + ret + +endp + ;;================================================================================================;; proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;; @@ -716,7 +966,21 @@ endl endp +; in: eax = number +; edi = ptr where to store ascii +ascii_dec: + mov ecx, 10 + .loop: + xor edx, edx + div ecx + add dl, '0' + mov byte[edi], dl + inc edi + test eax, eax + jnz .loop + + ret ;;================================================================================================;; @@ -759,11 +1023,11 @@ export \ lib_init , 'lib_init' , \ 0x00010001 , 'version' , \ HTTP_get , 'get' , \ + HTTP_head , 'head' , \ + HTTP_post , 'post' , \ find_header_field , 'find_header_field' , \ HTTP_process , 'process' -; HTTP_head , 'head' , \ -; HTTP_post , 'post' , \ ; HTTP_put , 'put' , \ ; HTTP_delete , 'delete' , \ ; HTTP_trace , 'trace' , \ @@ -783,6 +1047,10 @@ key_password db 'password', 0 str_http11 db ' HTTP/1.1', 13, 10, 'Host: ' .length = $ - str_http11 +str_post_cl db 13, 10, 'Content-Length: ' + .length = $ - str_post_cl +str_post_ct db 13, 10, 'Content-Type: ' + .length = $ - str_post_ct str_close db 13, 10, 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10 .length = $ - str_close str_proxy_auth db 13, 10, 'Proxy-Authorization: Basic ' @@ -794,6 +1062,9 @@ base64_table db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' str_cl db 'content-length', 0 str_slash db '/', 0 str_te db 'transfer-encoding', 0 +str_get db 'GET ', 0 +str_head db 'HEAD ', 0 +str_post db 'POST ', 0 include_debug_strings