pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / genlib / net / http / httpreadwrite.c
1 /*******************************************************************************
2  *
3  * Copyright (c) 2000-2003 Intel Corporation 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met: 
8  *
9  * - Redistributions of source code must retain the above copyright notice, 
10  * this list of conditions and the following disclaimer. 
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  * this list of conditions and the following disclaimer in the documentation 
13  * and/or other materials provided with the distribution. 
14  * - Neither name of Intel Corporation nor the names of its contributors 
15  * may be used to endorse or promote products derived from this software 
16  * without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  ******************************************************************************/
31
32
33 /************************************************************************
34 * Purpose: This file defines the functionality making use of the http 
35 * It defines functions to receive messages, process messages, send 
36 * messages
37 ************************************************************************/
38
39
40 #include "config.h"
41
42
43 #include "httpreadwrite.h"
44
45
46 #include "unixutil.h"
47 #include "upnp.h"
48 #include "upnpapi.h"
49 #include "membuffer.h"
50 #include "uri.h"
51 #include "statcodes.h"
52 #include "sock.h"
53 #include "webserver.h"
54
55
56 #include <assert.h>
57 #include <stdarg.h>
58
59
60 #ifndef UPNP_USE_BCBPP
61         #ifndef UPNP_USE_MSVCPP
62                 #include <inttypes.h>
63                 #include <stdint.h>
64         #endif
65 #endif
66
67
68 #ifdef WIN32
69         #include <winsock2.h>
70         #include <malloc.h>
71 #else
72         #include <arpa/inet.h>
73         #include <fcntl.h>
74         #include <netinet/in.h>
75         #include <sys/types.h>
76         #include <sys/socket.h>
77         #include <sys/time.h>
78         #include <sys/wait.h>
79         #include <unistd.h>
80         #include <sys/utsname.h>
81 #endif
82
83
84 /* 
85  * Please, do not change these to const int while MSVC cannot understand
86  * const int in array dimensions.
87  */
88 /*
89 const int CHUNK_HEADER_SIZE = 10;
90 const int CHUNK_TAIL_SIZE = 10;
91 */
92 #define CHUNK_HEADER_SIZE 10
93 #define CHUNK_TAIL_SIZE 10
94
95
96 /************************************************************************
97  * Function: http_FixUrl
98  *
99  * Parameters:
100  *      IN uri_type* url;               URL to be validated and fixed
101  *      OUT uri_type* fixed_url;        URL after being fixed.
102  *
103  * Description:
104  *      Validates URL
105  *
106  * Returns:
107  *       UPNP_E_INVALID_URL
108  *       UPNP_E_SUCCESS
109  ************************************************************************/
110 int
111 http_FixUrl( IN uri_type * url,
112              OUT uri_type * fixed_url )
113 {
114     char *temp_path = "/";
115
116     *fixed_url = *url;
117
118     if( token_string_casecmp( &fixed_url->scheme, "http" ) != 0 ) {
119         return UPNP_E_INVALID_URL;
120     }
121
122     if( fixed_url->hostport.text.size == 0 ) {
123         return UPNP_E_INVALID_URL;
124     }
125     // set pathquery to "/" if it is empty
126     if( fixed_url->pathquery.size == 0 ) {
127         fixed_url->pathquery.buff = temp_path;
128         fixed_url->pathquery.size = 1;
129     }
130
131     return UPNP_E_SUCCESS;
132 }
133
134
135 /************************************************************************
136  * Function: http_FixStrUrl
137  *
138  * Parameters:
139  *      IN const char* urlstr;          Character string as a URL
140  *      IN int urlstrlen;               Length of the character string
141  *      OUT uri_type* fixed_url;        Fixed and corrected URL
142  *
143  * Description:
144  *      Parses URL and then validates URL
145  *
146  * Returns:
147  *       UPNP_E_INVALID_URL
148  *       UPNP_E_SUCCESS
149  ************************************************************************/
150 int
151 http_FixStrUrl( IN const char *urlstr,
152                 IN int urlstrlen,
153                 OUT uri_type * fixed_url )
154 {
155     uri_type url;
156
157     if( parse_uri( urlstr, urlstrlen, &url ) != HTTP_SUCCESS ) {
158         return UPNP_E_INVALID_URL;
159     }
160
161     return http_FixUrl( &url, fixed_url );
162 }
163
164
165 /************************************************************************
166  * Function: http_Connect
167  *
168  * Parameters:
169  *      IN uri_type* destination_url;   URL containing destination information
170  *      OUT uri_type *url;              Fixed and corrected URL
171  *
172  * Description:
173  *      Gets destination address from URL and then connects to the remote end
174  *
175  *  Returns:
176  *      socket descriptor on sucess
177  *      UPNP_E_OUTOF_SOCKET
178  *      UPNP_E_SOCKET_CONNECT on error
179  ************************************************************************/
180 int
181 http_Connect( IN uri_type * destination_url,
182               OUT uri_type * url )
183 {
184     int connfd;
185
186     http_FixUrl( destination_url, url );
187
188     connfd = socket( AF_INET, SOCK_STREAM, 0 );
189     if( connfd == -1 ) {
190         return UPNP_E_OUTOF_SOCKET;
191     }
192
193     if( connect( connfd, ( struct sockaddr * )&url->hostport.IPv4address,
194                  sizeof( struct sockaddr_in ) ) == -1 ) {
195 #ifdef WIN32
196         UpnpPrintf(UPNP_CRITICAL, HTTP, __FILE__, __LINE__,
197             "connect error: %d\n", WSAGetLastError());
198 #endif
199         shutdown( connfd, SD_BOTH );
200         UpnpCloseSocket( connfd );
201         return UPNP_E_SOCKET_CONNECT;
202     }
203
204     return connfd;
205 }
206
207
208 /*!
209  * \brief Get the data on the socket and take actions based on the read data to
210  * modify the parser objects buffer.
211  *
212  * If an error is reported while parsing the data, the error code is passed in
213  * the http_errr_code parameter.
214  *
215  * Parameters:
216  *      IN SOCKINFO *info;                      Socket information object
217  *      OUT http_parser_t* parser;              HTTP parser object
218  *      IN http_method_t request_method;        HTTP request method
219  *      IN OUT int* timeout_secs;               time out
220  *      OUT int* http_error_code;               HTTP error code returned
221  *
222  * \return
223  *       UPNP_E_SUCCESS
224  *       UPNP_E_BAD_HTTPMSG
225  */
226 int http_RecvMessage(
227         IN SOCKINFO *info,
228         OUT http_parser_t *parser,
229         IN http_method_t request_method,
230         IN OUT int *timeout_secs,
231         OUT int *http_error_code)
232 {
233         int ret = UPNP_E_SUCCESS;
234         int line = 0;
235         parse_status_t status;
236         int num_read;
237         xboolean ok_on_close = FALSE;
238         char buf[2 * 1024];
239
240         if (request_method == HTTPMETHOD_UNKNOWN) {
241                 parser_request_init(parser);
242         } else {
243                 parser_response_init(parser, request_method);
244         }
245
246         while (TRUE) {
247                 num_read = sock_read(info, buf, sizeof buf, timeout_secs);
248                 if (num_read > 0) {
249                         // got data
250                         status = parser_append(parser, buf, num_read);
251                         if (status == PARSE_SUCCESS) {
252                                 UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
253                                         "<<< (RECVD) <<<\n%s\n-----------------\n",
254                                         parser->msg.msg.buf );
255                                 print_http_headers( &parser->msg );
256                                 if (parser->content_length > (unsigned int)g_maxContentLength) {
257                                         *http_error_code = HTTP_REQ_ENTITY_TOO_LARGE;
258                                         line = __LINE__;
259                                         ret = UPNP_E_OUTOF_BOUNDS;
260                                         goto ExitFunction;
261                                 }
262                                 line = __LINE__;
263                                 ret = 0;
264                                 goto ExitFunction;
265                         } else if (status == PARSE_FAILURE) {
266                                 *http_error_code = parser->http_error_code;
267                                 line = __LINE__;
268                                 ret = UPNP_E_BAD_HTTPMSG;
269                                 goto ExitFunction;
270                         } else if (status == PARSE_INCOMPLETE_ENTITY) {
271                                 // read until close
272                                 ok_on_close = TRUE;
273                         } else if (status == PARSE_CONTINUE_1) {
274                                 // Web post request.
275                                 line = __LINE__;
276                                 ret = PARSE_SUCCESS;
277                                 goto ExitFunction;
278                         }
279                 } else if (num_read == 0) {
280                         if (ok_on_close) {
281                                 UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
282                                         "<<< (RECVD) <<<\n%s\n-----------------\n",
283                                         parser->msg.msg.buf );
284                                 print_http_headers(&parser->msg);
285                                 line = __LINE__;
286                                 ret = 0;
287                                 goto ExitFunction;
288                         } else {
289                                 // partial msg
290                                 *http_error_code = HTTP_BAD_REQUEST;    // or response
291                                 line = __LINE__;
292                                 ret = UPNP_E_BAD_HTTPMSG;
293                                 goto ExitFunction;
294                         }
295                 } else {
296                         *http_error_code = parser->http_error_code;
297                         line = __LINE__;
298                         ret = num_read;
299                         goto ExitFunction;
300                 }
301         }
302
303 ExitFunction:
304         if (ret != UPNP_E_SUCCESS) {
305                 UpnpPrintf(UPNP_ALL, HTTP, __FILE__, line,
306                         "(http_RecvMessage): Error %d, http_error_code = %d.\n",
307                         ret,
308                         *http_error_code);
309         }
310
311         return ret;
312 }
313
314
315 /************************************************************************
316  * Function: http_SendMessage
317  *
318  * Parameters:
319  *      IN SOCKINFO *info ;             Socket information object
320  *      IN OUT int * TimeOut ;          time out value
321  *      IN const char* fmt, ...  Pattern format to take actions upon
322  *
323  * Description:
324  *      Sends a message to the destination based on the
325  *      IN const char* fmt parameter
326  *      fmt types:
327  *              'f':    arg = const char * file name
328  *              'm':    arg1 = const char * mem_buffer; arg2= size_t buf_length
329  *      E.g.:
330  *              char *buf = "POST /xyz.cgi http/1.1\r\n\r\n";
331  *              char *filename = "foo.dat";
332  *              int status = http_SendMessage( tcpsock, "mf",
333  *                      buf, strlen(buf),       // args for memory buffer
334  *                      filename );             // arg for file
335  *
336  * Returns:
337  *      UPNP_E_OUTOF_MEMORY
338  *      UPNP_E_FILE_READ_ERROR
339  *      UPNP_E_SUCCESS
340  ************************************************************************/
341 int
342 http_SendMessage( IN SOCKINFO * info,
343                   IN OUT int *TimeOut,
344                   IN const char *fmt,
345                   ... )
346 {
347     char c;
348     char *buf = NULL;
349     size_t buf_length;
350     char *filename = NULL;
351     FILE *Fp;
352     int num_read;
353     int num_written;
354     off_t amount_to_be_read = 0;
355     va_list argp;
356     char *file_buf = NULL;
357     char *ChunkBuf = NULL;
358     struct SendInstruction *Instr = NULL;
359     char Chunk_Header[CHUNK_HEADER_SIZE];
360     int RetVal = 0;
361
362     // 10 byte allocated for chunk header.
363     int Data_Buf_Size = WEB_SERVER_BUF_SIZE;
364
365     va_start( argp, fmt );
366
367     while( ( c = *fmt++ ) != 0 ) {
368         if( c == 'I' ) {
369             Instr = va_arg(argp, struct SendInstruction *);
370
371             assert( Instr );
372
373             if( Instr->ReadSendSize >= 0 ) {
374                 amount_to_be_read = Instr->ReadSendSize;
375             } else {
376                 amount_to_be_read = Data_Buf_Size;
377             }
378
379             if( amount_to_be_read < WEB_SERVER_BUF_SIZE ) {
380                 Data_Buf_Size = amount_to_be_read;
381             }
382
383             ChunkBuf = (char *)malloc(
384                 Data_Buf_Size + CHUNK_HEADER_SIZE + CHUNK_TAIL_SIZE);
385             if( !ChunkBuf ) {
386                 return UPNP_E_OUTOF_MEMORY;
387             }
388
389             file_buf = ChunkBuf + CHUNK_HEADER_SIZE;
390         } else if( c == 'f' ) {
391             // file name
392             filename = va_arg(argp, char *);
393             if( Instr && Instr->IsVirtualFile ) {
394                 Fp = (virtualDirCallback.open)( filename, UPNP_READ );
395             } else  {
396                 Fp = fopen( filename, "rb" );
397             }
398             if( Fp == NULL ) {
399                 free( ChunkBuf );
400                 return UPNP_E_FILE_READ_ERROR;
401             }
402
403             if( Instr && Instr->IsRangeActive && Instr->IsVirtualFile ) {
404                 if( virtualDirCallback.seek( Fp, Instr->RangeOffset,
405                                              SEEK_CUR ) != 0 ) {
406                     free( ChunkBuf );
407                     return UPNP_E_FILE_READ_ERROR;
408                 }
409             } else if( Instr && Instr->IsRangeActive ) {
410                 if( fseeko( Fp, Instr->RangeOffset, SEEK_CUR ) != 0 ) {
411                     free( ChunkBuf );
412                     return UPNP_E_FILE_READ_ERROR;
413                 }
414             }
415
416             while( amount_to_be_read ) {
417                 if( Instr ) {
418                     int n = (amount_to_be_read >= Data_Buf_Size) ?
419                         Data_Buf_Size : amount_to_be_read;
420                     if( Instr->IsVirtualFile ) {
421                         num_read = virtualDirCallback.read( Fp, file_buf, n );
422                     } else {
423                         num_read = fread( file_buf, 1, n, Fp );
424                     }
425                     amount_to_be_read = amount_to_be_read - num_read;
426                     if( Instr->ReadSendSize < 0 ) {
427                         // read until close
428                         amount_to_be_read = Data_Buf_Size;
429                     }
430                 } else {
431                     num_read = fread( file_buf, 1, Data_Buf_Size, Fp );
432                 }
433
434                 if( num_read == 0 ) {
435                     // EOF so no more to send.
436                     if( Instr && Instr->IsChunkActive ) {
437                         char *str = "0\r\n\r\n";
438                         num_written = sock_write(info, str, strlen(str), TimeOut);
439                     } else {
440                         RetVal = UPNP_E_FILE_READ_ERROR;
441                     }
442                     goto Cleanup_File;
443                 }
444                 // Create chunk for the current buffer.
445                 if( Instr && Instr->IsChunkActive ) {
446                     // Copy CRLF at the end of the chunk
447                     memcpy( file_buf + num_read, "\r\n", 2 );
448
449                     // Hex length for the chunk size.
450                     sprintf( Chunk_Header, "%x", num_read );
451
452                     //itoa(num_read,Chunk_Header,16); 
453                     strcat( Chunk_Header, "\r\n" );
454
455                     // Copy the chunk size header 
456                     memcpy( file_buf - strlen( Chunk_Header ),
457                             Chunk_Header, strlen( Chunk_Header ) );
458
459                     // on the top of the buffer.
460                     //file_buf[num_read+strlen(Chunk_Header)] = NULL;
461                     //printf("Sending %s\n",file_buf-strlen(Chunk_Header));
462                     num_written = sock_write(
463                         info, file_buf - strlen( Chunk_Header ),
464                         num_read + strlen( Chunk_Header ) + 2, TimeOut );
465
466                     if( num_written !=
467                         num_read + ( int )strlen( Chunk_Header ) + 2 ) {
468                         // Send error nothing we can do.
469                         goto Cleanup_File;
470                     }
471                 } else {
472                     // write data
473                     num_written = sock_write( info, file_buf, num_read, TimeOut );
474                     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
475                         ">>> (SENT) >>>\n%.*s\n------------\n",
476                         ( int )num_written, file_buf );
477                     // Send error nothing we can do
478                     if( num_written != num_read ) {
479                         goto Cleanup_File;
480                     }
481                 }
482             } // while
483 Cleanup_File:
484             va_end( argp );
485             if( Instr && Instr->IsVirtualFile ) {
486                 virtualDirCallback.close( Fp );
487             } else {
488                 fclose( Fp );
489             }
490             free( ChunkBuf );
491             return RetVal;
492
493         } else if( c == 'b' ) {
494             // memory buffer
495             buf = va_arg(argp, char *);
496             buf_length = va_arg(argp, size_t);
497             if( buf_length > 0 ) {
498                 num_written = sock_write( info, buf, buf_length, TimeOut );
499                 UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
500                     ">>> (SENT) >>>\n"
501                     "%.*s\nbuf_length=%d, num_written=%d\n"
502                     "------------\n",
503                     (int)buf_length, buf, (int)buf_length, num_written );
504                 if( (size_t)num_written != buf_length ) {
505                     goto end;
506                 }
507             }
508         }
509     }
510
511 end:
512     va_end( argp );
513     free( ChunkBuf );
514     return 0;
515 }
516
517
518 /************************************************************************
519  * Function: http_RequestAndResponse
520  *
521  * Parameters:
522  *      IN uri_type* destination;       Destination URI object which contains
523  *                                      remote IP address among other elements
524  *      IN const char* request;         Request to be sent
525  *      IN size_t request_length;       Length of the request
526  *      IN http_method_t req_method;    HTTP Request method
527  *      IN int timeout_secs;            time out value
528  *      OUT http_parser_t* response;    Parser object to receive the repsonse
529  *
530  * Description:
531  *      Initiates socket, connects to the destination, sends a
532  *      request and waits for the response from the remote end
533  *
534  * Returns:
535  *      UPNP_E_SOCKET_ERROR
536  *      UPNP_E_SOCKET_CONNECT
537  *      Error Codes returned by http_SendMessage
538  *      Error Codes returned by http_RecvMessage
539  ************************************************************************/
540 int
541 http_RequestAndResponse( IN uri_type * destination,
542                          IN const char *request,
543                          IN size_t request_length,
544                          IN http_method_t req_method,
545                          IN int timeout_secs,
546                          OUT http_parser_t * response )
547 {
548     int tcp_connection;
549     int ret_code;
550     int http_error_code;
551     SOCKINFO info;
552
553     tcp_connection = socket( AF_INET, SOCK_STREAM, 0 );
554     if( tcp_connection == -1 ) {
555         parser_response_init( response, req_method );
556         return UPNP_E_SOCKET_ERROR;
557     }
558     if( sock_init( &info, tcp_connection ) != UPNP_E_SUCCESS )
559     {
560         sock_destroy( &info, SD_BOTH );
561         parser_response_init( response, req_method );
562         return UPNP_E_SOCKET_ERROR;
563     }
564     // connect
565     ret_code = connect( info.socket,
566                         ( struct sockaddr * )&destination->hostport.
567                         IPv4address, sizeof( struct sockaddr_in ) );
568
569     if( ret_code == -1 ) {
570         sock_destroy( &info, SD_BOTH );
571         parser_response_init( response, req_method );
572         return UPNP_E_SOCKET_CONNECT;
573     }
574     // send request
575     ret_code = http_SendMessage( &info, &timeout_secs, "b",
576                                  request, request_length );
577     if( ret_code != 0 ) {
578         sock_destroy( &info, SD_BOTH );
579         parser_response_init( response, req_method );
580         return ret_code;
581     }
582     // recv response
583     ret_code = http_RecvMessage( &info, response, req_method,
584                                  &timeout_secs, &http_error_code );
585
586     sock_destroy( &info, SD_BOTH ); //should shutdown completely
587
588     return ret_code;
589 }
590
591
592 /************************************************************************
593  * Function: http_Download
594  *
595  * Parameters:
596  *      IN const char* url_str; String as a URL
597  *      IN int timeout_secs;    time out value
598  *      OUT char** document;    buffer to store the document extracted
599  *                              from the donloaded message.
600  *      OUT int* doc_length;    length of the extracted document
601  *      OUT char* content_type; Type of content
602  *
603  * Description:
604  *      Download the document message and extract the document 
605  *      from the message.
606  *
607  * Return: int
608  *      UPNP_E_SUCCESS
609  *      UPNP_E_INVALID_URL
610  ************************************************************************/
611 int
612 http_Download( IN const char *url_str,
613                IN int timeout_secs,
614                OUT char **document,
615                OUT int *doc_length,
616                OUT char *content_type )
617 {
618     int ret_code;
619     uri_type url;
620     char *msg_start;
621     char *entity_start;
622     char *hoststr;
623     char *temp;
624     http_parser_t response;
625     size_t msg_length;
626     size_t hostlen;
627     memptr ctype;
628     size_t copy_len;
629     membuffer request;
630     char *urlPath = alloca( strlen( url_str ) + 1 );
631
632     //ret_code = parse_uri( (char*)url_str, strlen(url_str), &url );
633     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, "DOWNLOAD URL : %s\n",
634         url_str );
635     ret_code =
636         http_FixStrUrl( ( char * )url_str, strlen( url_str ), &url );
637     if( ret_code != UPNP_E_SUCCESS ) {
638         return ret_code;
639     }
640     // make msg
641     membuffer_init( &request );
642
643     strcpy( urlPath, url_str );
644     hoststr = strstr( urlPath, "//" );
645     if( hoststr == NULL ) {
646         return UPNP_E_INVALID_URL;
647     }
648
649     hoststr += 2;
650     temp = strchr( hoststr, '/' );
651     if( temp == NULL ) {
652         return UPNP_E_INVALID_URL;
653     }
654
655     *temp = '\0';
656     hostlen = strlen( hoststr );
657     *temp = '/';
658     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
659         "HOSTNAME : %s Length : %"PRIzu"\n", hoststr, hostlen );
660
661     ret_code = http_MakeMessage(
662         &request, 1, 1,
663         "Q" "s" "bcDCUc",
664         HTTPMETHOD_GET, url.pathquery.buff, url.pathquery.size,
665         "HOST: ",
666         hoststr, hostlen );
667     if( ret_code != 0 ) {
668         UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
669             "HTTP Makemessage failed\n" );
670             membuffer_destroy( &request );
671         return ret_code;
672     }
673
674     UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
675         "HTTP Buffer:\n%s\n" "----------END--------\n",
676         request.buf);
677     // get doc msg
678     ret_code =
679         http_RequestAndResponse( &url, request.buf, request.length,
680                                  HTTPMETHOD_GET, timeout_secs, &response );
681
682     if( ret_code != 0 ) {
683         httpmsg_destroy( &response.msg );
684         membuffer_destroy( &request );
685         return ret_code;
686     }
687
688     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__, "Response\n" );
689     print_http_headers( &response.msg );
690
691         // optional content-type
692         if( content_type ) {
693         if( httpmsg_find_hdr( &response.msg, HDR_CONTENT_TYPE, &ctype ) ==
694             NULL ) {
695             *content_type = '\0';   // no content-type
696         } else {
697             // safety
698             copy_len = ctype.length < LINE_SIZE - 1 ?
699                 ctype.length : LINE_SIZE - 1;
700
701             memcpy( content_type, ctype.buf, copy_len );
702             content_type[copy_len] = '\0';
703         }
704     }
705     //
706     // extract doc from msg
707     //
708
709     if( ( *doc_length = ( int )response.msg.entity.length ) == 0 ) {
710         // 0-length msg
711         *document = NULL;
712     } else if( response.msg.status_code == HTTP_OK ) {
713         //LEAK_FIX_MK
714         // copy entity
715         entity_start = response.msg.entity.buf; // what we want
716         msg_length = response.msg.msg.length;   // save for posterity   
717         msg_start = membuffer_detach( &response.msg.msg );  // whole msg
718
719         // move entity to the start; copy null-terminator too
720         memmove( msg_start, entity_start, *doc_length + 1 );
721
722         // save mem for body only
723         *document = realloc( msg_start, *doc_length + 1 );  //LEAK_FIX_MK
724         // *document = Realloc( msg_start,msg_length, *doc_length + 1 );//LEAK_FIX_MK
725
726         // shrink can't fail
727         assert( ( int )msg_length > *doc_length );
728         assert( *document != NULL );
729     }
730
731     if( response.msg.status_code == HTTP_OK ) {
732         ret_code = 0;           // success
733     } else {
734         // server sent error msg (not requested doc)
735         ret_code = response.msg.status_code;
736     }
737
738     httpmsg_destroy( &response.msg );
739     membuffer_destroy( &request );
740
741     return ret_code;
742 }
743
744 typedef struct HTTPPOSTHANDLE {
745     SOCKINFO sock_info;
746     int contentLength;
747 } http_post_handle_t;
748
749 /************************************************************************
750  * Function: MakePostMessage
751  *
752  * Parameters:
753  *      const char *url_str;            String as a URL
754  *      membuffer *request;             Buffer containing the request
755  *      uri_type *url;                  URI object containing the scheme,
756  *                                      path query token, etc.
757  *      int contentLength;              length of content
758  *      const char *contentType;        Type of content
759  *
760  * Description:
761  *      Makes the message for the HTTP POST message
762  *
763  * Returns:
764  *      UPNP_E_INVALID_URL
765  *      UPNP_E_INVALID_PARAM
766  *      UPNP_E_SUCCESS
767  ************************************************************************/
768 int
769 MakePostMessage( const char *url_str,
770                  membuffer * request,
771                  uri_type * url,
772                  int contentLength,
773                  const char *contentType )
774 {
775     int ret_code = 0;
776     char *urlPath = alloca( strlen( url_str ) + 1 );
777     size_t hostlen = 0;
778     char *hoststr,
779      *temp;
780
781     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
782                          "DOWNLOAD URL : %s\n", url_str );
783     ret_code =
784         http_FixStrUrl( ( char * )url_str, strlen( url_str ), url );
785     if( ret_code != UPNP_E_SUCCESS ) {
786         return ret_code;
787     }
788     // make msg
789     membuffer_init( request );
790
791     strcpy( urlPath, url_str );
792     hoststr = strstr( urlPath, "//" );
793     if( hoststr == NULL ) {
794         return UPNP_E_INVALID_URL;
795     }
796
797     hoststr += 2;
798     temp = strchr( hoststr, '/' );
799     if( temp == NULL ) {
800         return UPNP_E_INVALID_URL;
801     }
802
803     *temp = '\0';
804     hostlen = strlen( hoststr );
805     *temp = '/';
806     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
807         "HOSTNAME : %s Length : %"PRIzu"\n", hoststr, hostlen );
808
809     if( contentLength >= 0 ) {
810         ret_code = http_MakeMessage(
811             request, 1, 1,
812             "Q" "s" "bcDCU" "T" "Nc",
813             HTTPMETHOD_POST, url->pathquery.buff, url->pathquery.size,
814             "HOST: ",
815             hoststr, hostlen,
816             contentType,
817             (off_t)contentLength );
818     } else if( contentLength == UPNP_USING_CHUNKED ) {
819         ret_code = http_MakeMessage(
820             request, 1, 1,
821             "Q" "s" "bcDCU" "TKc",
822             HTTPMETHOD_POST, url->pathquery.buff, url->pathquery.size,
823             "HOST: ",
824             hoststr, hostlen,
825             contentType );
826     } else if( contentLength == UPNP_UNTIL_CLOSE ) {
827         ret_code = http_MakeMessage(
828             request, 1, 1,
829             "Q" "s" "bcDCU" "Tc",
830             HTTPMETHOD_POST, url->pathquery.buff, url->pathquery.size,
831             "HOST: ",
832             hoststr, hostlen,
833             contentType );
834     } else {
835         ret_code = UPNP_E_INVALID_PARAM;
836     }
837
838     if( ret_code != 0 ) {
839         UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
840             "HTTP Makemessage failed\n" );
841         membuffer_destroy( request );
842
843         return ret_code;
844     }
845
846     UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
847         "HTTP Buffer:\n%s\n" "----------END--------\n",
848         request->buf);
849
850     return UPNP_E_SUCCESS;
851 }
852
853 /************************************************************************
854  * Function: http_WriteHttpPost
855  *
856  * Parameters:
857  *      IN void *Handle:        Handle to the http post object
858  *      IN char *buf:           Buffer to send to peer, if format used
859  *                              is not UPNP_USING_CHUNKED, 
860  *      IN unsigned int *size:  Size of the data to be sent.
861  *      IN int timeout:         time out value
862  *
863  * Description:
864  *      Formats data if format used is UPNP_USING_CHUNKED.
865  *      Writes data on the socket connected to the peer.
866  *
867  * Return: int
868  *      UPNP_E_SUCCESS - On Success
869  *      UPNP_E_INVALID_PARAM - Invalid Parameter
870  *      -1 - On Socket Error.
871  ************************************************************************/
872 int
873 http_WriteHttpPost( IN void *Handle,
874                     IN char *buf,
875                     IN unsigned int *size,
876                     IN int timeout )
877 {
878     http_post_handle_t *handle = ( http_post_handle_t * ) Handle;
879     char *tempbuf = NULL;
880     int tempbufSize = 0;
881     int freeTempbuf = 0;
882     int numWritten = 0;
883
884     if( ( !handle ) || ( !size ) || ( ( ( *size ) > 0 ) && !buf )
885         || ( ( *size ) < 0 ) ) {
886         if(size) ( *size ) = 0;
887         return UPNP_E_INVALID_PARAM;
888     }
889     if( handle->contentLength == UPNP_USING_CHUNKED ) {
890         if( ( *size ) ) {
891             int tempSize = 0;
892             tempbuf = ( char * )malloc(
893                 *size + CHUNK_HEADER_SIZE + CHUNK_TAIL_SIZE );
894             if ( tempbuf == NULL) {
895                 return UPNP_E_OUTOF_MEMORY;
896             }
897
898             // begin chunk
899             sprintf( tempbuf, "%x\r\n", ( *size ) );
900             tempSize = strlen( tempbuf );
901             memcpy( tempbuf + tempSize, buf, ( *size ) );
902             memcpy( tempbuf + tempSize + ( *size ), "\r\n", 2 );
903             // end of chunk
904             tempbufSize = tempSize + ( *size ) + 2;
905             freeTempbuf = 1;
906         }
907     } else {
908         tempbuf = buf;
909         tempbufSize = ( *size );
910     }
911
912     numWritten =
913         sock_write( &handle->sock_info, tempbuf, tempbufSize, &timeout );
914     //(*size) = sock_write(&handle->sock_info,tempbuf,tempbufSize,&timeout);
915
916     if( freeTempbuf ) {
917         free( tempbuf );
918     }
919     if( numWritten < 0 ) {
920         ( *size ) = 0;
921         return numWritten;
922     } else {
923         ( *size ) = numWritten;
924         return UPNP_E_SUCCESS;
925     }
926 }
927
928 /************************************************************************
929  * Function: http_CloseHttpPost
930  *
931  * Parameters:
932  *      IN void *Handle;        Handle to the http post object
933  *      IN OUT int *httpStatus; HTTP status returned on receiving a
934  *                              response message
935  *      IN int timeout;         time out value
936  *
937  * Description:
938  *      Sends remaining data if using  UPNP_USING_CHUNKED 
939  *      format. Receives any more messages. Destroys socket and any socket
940  *      associated memory. Frees handle associated with the HTTP POST msg.
941  *
942  * Return: int
943  *      UPNP_E_SUCCESS          - On Sucess
944  *      UPNP_E_INVALID_PARAM    - Invalid Parameter
945  ************************************************************************/
946 int
947 http_CloseHttpPost( IN void *Handle,
948                     IN OUT int *httpStatus,
949                     IN int timeout )
950 {
951     int retc = 0;
952     http_parser_t response;
953     int http_error_code;
954
955     http_post_handle_t *handle = Handle;
956
957     if( ( !handle ) || ( !httpStatus ) ) {
958         return UPNP_E_INVALID_PARAM;
959     }
960
961     if( handle->contentLength == UPNP_USING_CHUNKED ) {
962         retc = sock_write( &handle->sock_info, "0\r\n\r\n", strlen( "0\r\n\r\n" ), &timeout );  //send last chunk
963     }
964     //read response
965     parser_response_init( &response, HTTPMETHOD_POST );
966
967     retc =
968         http_RecvMessage( &handle->sock_info, &response, HTTPMETHOD_POST,
969                           &timeout, &http_error_code );
970
971     ( *httpStatus ) = http_error_code;
972
973     sock_destroy( &handle->sock_info, SD_BOTH );    //should shutdown completely
974
975     httpmsg_destroy( &response.msg );
976     free( handle );
977
978     return retc;
979 }
980
981 /************************************************************************
982  * Function: http_OpenHttpPost
983  *
984  * Parameters:
985  *      IN const char *url_str;         String as a URL 
986  *      IN OUT void **Handle;           Pointer to buffer to store HTTP
987  *                                      post handle
988  *      IN const char *contentType;     Type of content
989  *      IN int contentLength;           length of content
990  *      IN int timeout;                 time out value
991  *
992  * Description:
993  *      Makes the HTTP POST message, connects to the peer, 
994  *      sends the HTTP POST request. Adds the post handle to buffer of 
995  *      such handles
996  *
997  * Return : int;
998  *      UPNP_E_SUCCESS          - On Sucess
999  *      UPNP_E_INVALID_PARAM    - Invalid Parameter
1000  *      UPNP_E_OUTOF_MEMORY
1001  *      UPNP_E_SOCKET_ERROR
1002  *      UPNP_E_SOCKET_CONNECT
1003  ************************************************************************/
1004 int
1005 http_OpenHttpPost( IN const char *url_str,
1006                    IN OUT void **Handle,
1007                    IN const char *contentType,
1008                    IN int contentLength,
1009                    IN int timeout )
1010 {
1011     int ret_code;
1012     int tcp_connection;
1013     membuffer request;
1014     http_post_handle_t *handle = NULL;
1015     uri_type url;
1016
1017     if( ( !url_str ) || ( !Handle ) || ( !contentType ) ) {
1018         return UPNP_E_INVALID_PARAM;
1019     }
1020
1021     ( *Handle ) = handle;
1022
1023     if( ( ret_code =
1024           MakePostMessage( url_str, &request, &url, contentLength,
1025                            contentType ) ) != UPNP_E_SUCCESS ) {
1026         return ret_code;
1027     }
1028
1029     handle =
1030         ( http_post_handle_t * ) malloc( sizeof( http_post_handle_t ) );
1031
1032     if( handle == NULL ) {
1033         return UPNP_E_OUTOF_MEMORY;
1034     }
1035
1036     handle->contentLength = contentLength;
1037
1038     tcp_connection = socket( AF_INET, SOCK_STREAM, 0 );
1039     if( tcp_connection == -1 ) {
1040         ret_code = UPNP_E_SOCKET_ERROR;
1041         goto errorHandler;
1042     }
1043
1044     if( sock_init( &handle->sock_info, tcp_connection ) != UPNP_E_SUCCESS )
1045     {
1046         sock_destroy( &handle->sock_info, SD_BOTH );
1047         ret_code = UPNP_E_SOCKET_ERROR;
1048         goto errorHandler;
1049     }
1050
1051     ret_code = connect( handle->sock_info.socket,
1052                         ( struct sockaddr * )&url.hostport.IPv4address,
1053                         sizeof( struct sockaddr_in ) );
1054
1055     if( ret_code == -1 ) {
1056         sock_destroy( &handle->sock_info, SD_BOTH );
1057         ret_code = UPNP_E_SOCKET_CONNECT;
1058         goto errorHandler;
1059     }
1060     // send request
1061     ret_code = http_SendMessage( &handle->sock_info, &timeout, "b",
1062                                  request.buf, request.length );
1063     if( ret_code != 0 ) {
1064         sock_destroy( &handle->sock_info, SD_BOTH );
1065     }
1066
1067   errorHandler:
1068     membuffer_destroy( &request );
1069     ( *Handle ) = handle;
1070     return ret_code;
1071 }
1072
1073 typedef struct HTTPGETHANDLE {
1074     http_parser_t response;
1075     SOCKINFO sock_info;
1076     int entity_offset;
1077     int cancel;
1078 } http_get_handle_t;
1079
1080 /************************************************************************
1081 * Function: MakeGetMessage
1082 *
1083 * Parameters:
1084 *       const char *url_str ;   String as a URL
1085 *       const char *proxy_str ; String as a URL of proxy to use
1086 *       membuffer *request ;    Buffer containing the request
1087 *       uri_type *url ;         URI object containing the scheme, path 
1088 *                               query token, etc.
1089 *
1090 * Description:
1091 *       Makes the message for the HTTP GET method
1092 *
1093 * Returns:
1094 *       UPNP_E_INVALID_URL
1095 *       Error Codes returned by http_MakeMessage
1096 *       UPNP_E_SUCCESS
1097 ************************************************************************/
1098 int
1099 MakeGetMessage( const char *url_str,
1100                 const char *proxy_str,
1101                 membuffer * request,
1102                 uri_type * url )
1103 {
1104     int ret_code;
1105     char *urlPath = alloca( strlen( url_str ) + 1 );
1106     size_t querylen = 0;
1107     const char *querystr;
1108     size_t hostlen = 0;
1109     char *hoststr,
1110      *temp;
1111
1112     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
1113         "DOWNLOAD URL : %s\n", url_str );
1114
1115     ret_code =
1116         http_FixStrUrl( ( char * )url_str, strlen( url_str ), url );
1117
1118     if( ret_code != UPNP_E_SUCCESS ) {
1119         return ret_code;
1120     }
1121     // make msg
1122     membuffer_init( request );
1123
1124     strcpy( urlPath, url_str );
1125     hoststr = strstr( urlPath, "//" );
1126     if( hoststr == NULL ) {
1127         return UPNP_E_INVALID_URL;
1128     }
1129
1130     hoststr += 2;
1131     temp = strchr( hoststr, '/' );
1132     if( temp == NULL ) {
1133         return UPNP_E_INVALID_URL;
1134     }
1135
1136     *temp = '\0';
1137     hostlen = strlen( hoststr );
1138     *temp = '/';
1139     UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
1140         "HOSTNAME : %s Length : %"PRIzu"\n", hoststr, hostlen );
1141
1142     if( proxy_str ) {
1143         querystr = url_str;
1144         querylen = strlen( querystr );
1145     } else {
1146         querystr = url->pathquery.buff;
1147         querylen = url->pathquery.size;
1148     }
1149
1150     ret_code = http_MakeMessage(
1151         request, 1, 1,
1152         "Q" "s" "bcDCUc",
1153         HTTPMETHOD_GET, querystr, querylen,
1154         "HOST: ",
1155         hoststr, hostlen );
1156
1157     if( ret_code != 0 ) {
1158         UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
1159             "HTTP Makemessage failed\n" );
1160         membuffer_destroy( request );
1161
1162         return ret_code;
1163     }
1164
1165     UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
1166         "HTTP Buffer:\n%s\n" "----------END--------\n",
1167         request->buf);
1168
1169     return UPNP_E_SUCCESS;
1170 }
1171
1172 /************************************************************************
1173  * Function: ReadResponseLineAndHeaders
1174  *
1175  * Parameters:
1176  *      IN SOCKINFO *info;              Socket information object
1177  *      IN OUT http_parser_t *parser;   HTTP Parser object
1178  *      IN OUT int *timeout_secs;       time out value
1179  *      IN OUT int *http_error_code;    HTTP errror code returned
1180  *
1181  * Description:
1182  *      Parses already exiting data. If not complete reads more 
1183  *      data on the connected socket. The read data is then parsed. The 
1184  *      same methid is carried out for headers.
1185  *
1186  * Return: int
1187  *      PARSE_OK - On Success
1188  *      PARSE_FAILURE - Failure to parse data correctly
1189  *      UPNP_E_BAD_HTTPMSG - Socker read() returns an error
1190  ************************************************************************/
1191 int
1192 ReadResponseLineAndHeaders( IN SOCKINFO * info,
1193                             IN OUT http_parser_t * parser,
1194                             IN OUT int *timeout_secs,
1195                             IN OUT int *http_error_code )
1196 {
1197     parse_status_t status;
1198     int num_read;
1199     char buf[2 * 1024];
1200     int done = 0;
1201     int ret_code = 0;
1202
1203     //read response line
1204
1205     status = parser_parse_responseline( parser );
1206     if( status == PARSE_OK ) {
1207         done = 1;
1208     } else if( status == PARSE_INCOMPLETE ) {
1209         done = 0;
1210     } else {
1211         //error
1212         return status;
1213     }
1214
1215     while( !done ) {
1216         num_read = sock_read( info, buf, sizeof( buf ), timeout_secs );
1217         if( num_read > 0 ) {
1218             // append data to buffer
1219             ret_code = membuffer_append( &parser->msg.msg, buf, num_read );
1220             if( ret_code != 0 ) {
1221                 // set failure status
1222                 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
1223                 return PARSE_FAILURE;
1224             }
1225             status = parser_parse_responseline( parser );
1226             if( status == PARSE_OK ) {
1227                 done = 1;
1228             } else if( status == PARSE_INCOMPLETE ) {
1229                 done = 0;
1230             } else {
1231                 //error
1232                 return status;
1233             }
1234         } else if( num_read == 0 ) {
1235
1236             // partial msg
1237             *http_error_code = HTTP_BAD_REQUEST;    // or response
1238             return UPNP_E_BAD_HTTPMSG;
1239
1240         } else {
1241             *http_error_code = parser->http_error_code;
1242             return num_read;
1243         }
1244     }
1245
1246     done = 0;
1247
1248     status = parser_parse_headers( parser );
1249     if( ( status == PARSE_OK ) && ( parser->position == POS_ENTITY ) ) {
1250
1251         done = 1;
1252     } else if( status == PARSE_INCOMPLETE ) {
1253         done = 0;
1254     } else {
1255         //error
1256         return status;
1257     }
1258
1259     //read headers
1260     while( !done ) {
1261         num_read = sock_read( info, buf, sizeof( buf ), timeout_secs );
1262         if( num_read > 0 ) {
1263             // append data to buffer
1264             ret_code = membuffer_append( &parser->msg.msg, buf, num_read );
1265             if( ret_code != 0 ) {
1266                 // set failure status
1267                 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
1268                 return PARSE_FAILURE;
1269             }
1270             status = parser_parse_headers( parser );
1271             if( ( status == PARSE_OK )
1272                 && ( parser->position == POS_ENTITY ) ) {
1273
1274                 done = 1;
1275             } else if( status == PARSE_INCOMPLETE ) {
1276                 done = 0;
1277             } else {
1278                 //error
1279                 return status;
1280             }
1281         } else if( num_read == 0 ) {
1282
1283             // partial msg
1284             *http_error_code = HTTP_BAD_REQUEST;    // or response
1285             return UPNP_E_BAD_HTTPMSG;
1286
1287         } else {
1288             *http_error_code = parser->http_error_code;
1289             return num_read;
1290         }
1291     }
1292
1293     return PARSE_OK;
1294 }
1295
1296 /************************************************************************
1297  * Function: http_ReadHttpGet
1298  *
1299  * Parameters:
1300  *      IN void *Handle;                Handle to the HTTP get object
1301  *      IN OUT char *buf;               Buffer to get the read and parsed data
1302  *      IN OUT unsigned int *size;      Size of the buffer passed
1303  *      IN int timeout;                 time out value
1304  *
1305  * Description:
1306  *      Parses already existing data, then gets new data.
1307  *      Parses and extracts information from the new data.
1308  *
1309  * Return: int
1310  *      UPNP_E_SUCCESS          - On Sucess
1311  *      UPNP_E_INVALID_PARAM    - Invalid Parameter
1312  *      UPNP_E_BAD_RESPONSE
1313  *      UPNP_E_BAD_HTTPMSG
1314  *      UPNP_E_CANCELED
1315  ************************************************************************/
1316 int
1317 http_ReadHttpGet( IN void *Handle,
1318                   IN OUT char *buf,
1319                   IN OUT unsigned int *size,
1320                   IN int timeout )
1321 {
1322     http_get_handle_t *handle = Handle;
1323
1324     parse_status_t status;
1325     int num_read;
1326     xboolean ok_on_close = FALSE;
1327     char tempbuf[2 * 1024];
1328
1329     int ret_code = 0;
1330
1331     if( ( !handle ) || ( !size ) || ( ( ( *size ) > 0 ) && !buf )
1332         || ( ( *size ) < 0 ) ) {
1333         if(size) ( *size ) = 0;
1334         return UPNP_E_INVALID_PARAM;
1335     }
1336     //first parse what has already been gotten
1337     if( handle->response.position != POS_COMPLETE ) {
1338         status = parser_parse_entity( &handle->response );
1339     } else {
1340         status = PARSE_SUCCESS;
1341     }
1342
1343     if( status == PARSE_INCOMPLETE_ENTITY ) {
1344         // read until close
1345         ok_on_close = TRUE;
1346     } else if( ( status != PARSE_SUCCESS )
1347                && ( status != PARSE_CONTINUE_1 )
1348                && ( status != PARSE_INCOMPLETE ) ) {
1349         //error
1350         ( *size ) = 0;
1351         return UPNP_E_BAD_RESPONSE;
1352     }
1353     //read more if necessary entity
1354     while( ( ( handle->entity_offset + ( *size ) ) >
1355              handle->response.msg.entity.length )
1356            && ( ! handle->cancel )
1357            && ( handle->response.position != POS_COMPLETE ) ) {
1358         num_read =
1359             sock_read( &handle->sock_info, tempbuf, sizeof( tempbuf ),
1360                        &timeout );
1361         if( num_read > 0 ) {
1362             // append data to buffer
1363             ret_code = membuffer_append( &handle->response.msg.msg,
1364                                          tempbuf, num_read );
1365             if( ret_code != 0 ) {
1366                 // set failure status
1367                 handle->response.http_error_code =
1368                     HTTP_INTERNAL_SERVER_ERROR;
1369                 ( *size ) = 0;
1370                 return PARSE_FAILURE;
1371             }
1372             status = parser_parse_entity( &handle->response );
1373             if( status == PARSE_INCOMPLETE_ENTITY ) {
1374                 // read until close
1375                 ok_on_close = TRUE;
1376             } else if( ( status != PARSE_SUCCESS )
1377                        && ( status != PARSE_CONTINUE_1 )
1378                        && ( status != PARSE_INCOMPLETE ) ) {
1379                 //error
1380                 ( *size ) = 0;
1381                 return UPNP_E_BAD_RESPONSE;
1382             }
1383         } else if( num_read == 0 ) {
1384             if( ok_on_close ) {
1385                 UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
1386                     "<<< (RECVD) <<<\n%s\n-----------------\n",
1387                     handle->response.msg.msg.buf );
1388                     handle->response.position = POS_COMPLETE;
1389             } else {
1390                 // partial msg
1391                 ( *size ) = 0;
1392                 handle->response.http_error_code = HTTP_BAD_REQUEST;    // or response
1393                 return UPNP_E_BAD_HTTPMSG;
1394             }
1395         } else {
1396             ( *size ) = 0;
1397             return num_read;
1398         }
1399     }
1400
1401     if( ( handle->entity_offset + ( *size ) ) >
1402         handle->response.msg.entity.length ) {
1403         ( *size ) =
1404             handle->response.msg.entity.length - handle->entity_offset;
1405     }
1406
1407     memcpy( buf,
1408             &handle->response.msg.msg.buf[handle->
1409                                           response.entity_start_position +
1410                                           handle->entity_offset],
1411             ( *size ) );
1412     handle->entity_offset += ( *size );
1413
1414     if ( handle->cancel )
1415         return UPNP_E_CANCELED;
1416
1417     return UPNP_E_SUCCESS;
1418 }
1419
1420 /************************************************************************
1421  * Function: http_HttpGetProgress
1422  *
1423  * Parameters:
1424  *      IN void *Handle;                Handle to the HTTP get object
1425  *      OUT unsigned int *length;       Buffer to get the read and parsed data
1426  *      OUT unsigned int *total;        Size of tge buffer passed
1427  *
1428  * Description:
1429  *      Extracts information from the Handle to the HTTP get object.
1430  *
1431  * Return: int
1432  *      UPNP_E_SUCCESS          - On Sucess
1433  *      UPNP_E_INVALID_PARAM    - Invalid Parameter
1434  ************************************************************************/
1435 int http_HttpGetProgress( IN void *Handle, 
1436                       OUT unsigned int *length,
1437                       OUT unsigned int *total )
1438 {
1439     http_get_handle_t *handle = Handle;
1440
1441     if( ( !handle ) || ( !length ) || ( !total ) ) {
1442         return UPNP_E_INVALID_PARAM;
1443     }
1444     *length = handle->response.msg.entity.length;
1445     *total = handle->response.content_length;
1446     return UPNP_E_SUCCESS;
1447 }
1448
1449 /************************************************************************
1450  * Function: http_CancelHttpGet
1451  *
1452  * Parameters:
1453  *      IN void *Handle;        Handle to HTTP get object
1454  *
1455  * Description:
1456  *      Set the cancel flag of the HttpGet handle
1457  *
1458  * Return: int
1459  *      UPNP_E_SUCCESS          - On Success
1460  *      UPNP_E_INVALID_PARAM    - Invalid Parameter
1461  ************************************************************************/
1462 int
1463 http_CancelHttpGet( IN void *Handle )
1464 {
1465     http_get_handle_t *handle = Handle;
1466
1467     if( !handle ) {
1468         return UPNP_E_INVALID_PARAM;
1469     }
1470
1471     handle->cancel = 1;
1472
1473     return UPNP_E_SUCCESS;
1474 }
1475
1476
1477 /************************************************************************
1478  * Function: http_CloseHttpGet
1479  *
1480  * Parameters:
1481  *      IN void *Handle;        Handle to HTTP get object
1482  *
1483  * Description:
1484  *      Clears the handle allocated for the HTTP GET operation
1485  *      Clears socket states and memory allocated for socket operations. 
1486  *
1487  * Return: int
1488  *      UPNP_E_SUCCESS          - On Success
1489  *      UPNP_E_INVALID_PARAM    - Invalid Parameter
1490  ************************************************************************/
1491 int
1492 http_CloseHttpGet( IN void *Handle )
1493 {
1494     http_get_handle_t *handle = Handle;
1495
1496     if( !handle ) {
1497         return UPNP_E_INVALID_PARAM;
1498     }
1499
1500     sock_destroy( &handle->sock_info, SD_BOTH );    //should shutdown completely
1501     httpmsg_destroy( &handle->response.msg );
1502     handle->entity_offset = 0;
1503     free( handle );
1504     return UPNP_E_SUCCESS;
1505 }
1506
1507 /************************************************************************
1508  * Function: http_OpenHttpGet
1509  *
1510  * Parameters:
1511  *      IN const char *url_str:         String as a URL
1512  *      IN OUT void **Handle:           Pointer to buffer to store HTTP
1513  *                                      post handle
1514  *      IN OUT char **contentType:      Type of content
1515  *      OUT int *contentLength:         length of content
1516  *      OUT int *httpStatus:            HTTP status returned on receiving a
1517  *                                      response message
1518  *      IN int timeout:                 time out value
1519  *
1520  * Description:
1521  *      Makes the HTTP GET message, connects to the peer, 
1522  *      sends the HTTP GET request, gets the response and parses the 
1523  *      response.
1524  *
1525  * Return: int
1526  *      UPNP_E_SUCCESS          - On Success
1527  *      UPNP_E_INVALID_PARAM    - Invalid Paramters
1528  *      UPNP_E_OUTOF_MEMORY
1529  *      UPNP_E_SOCKET_ERROR
1530  *      UPNP_E_BAD_RESPONSE
1531  ************************************************************************/
1532 int
1533 http_OpenHttpGet( IN const char *url_str,
1534                   IN OUT void **Handle,
1535                   IN OUT char **contentType,
1536                   OUT int *contentLength,
1537                   OUT int *httpStatus,
1538                   IN int timeout )
1539 {
1540     return http_OpenHttpGetProxy(url_str, NULL, Handle, contentType, contentLength, httpStatus, timeout);
1541 }
1542
1543 /************************************************************************
1544  * Function: http_OpenHttpGetProxy
1545  *
1546  * Parameters:
1547  *      IN const char *url_str;         String as a URL
1548  *      IN const char *proxy_str;       String as a URL
1549  *      IN OUT void **Handle;           Pointer to buffer to store HTTP
1550  *                                      post handle
1551  *      IN OUT char **contentType;      Type of content
1552  *      OUT int *contentLength;         length of content
1553  *      OUT int *httpStatus;            HTTP status returned on receiving a
1554  *                                      response message
1555  *      IN int timeout:                 time out value
1556  *
1557  * Description:
1558  *      Makes the HTTP GET message, connects to the peer, 
1559  *      sends the HTTP GET request, gets the response and parses the response.
1560  *      If a proxy URL is defined then the connection is made there.
1561  *
1562  * Return: int
1563  *      UPNP_E_SUCCESS          - On Success
1564  *      UPNP_E_INVALID_PARAM    - Invalid Paramters
1565  *      UPNP_E_OUTOF_MEMORY
1566  *      UPNP_E_SOCKET_ERROR
1567  *      UPNP_E_BAD_RESPONSE
1568  ************************************************************************/
1569 int
1570 http_OpenHttpGetProxy( IN const char *url_str,
1571                   IN const char *proxy_str,
1572                   IN OUT void **Handle,
1573                   IN OUT char **contentType,
1574                   OUT int *contentLength,
1575                   OUT int *httpStatus,
1576                   IN int timeout )
1577 {
1578     int ret_code;
1579     int http_error_code;
1580     memptr ctype;
1581     int tcp_connection;
1582     membuffer request;
1583     http_get_handle_t *handle = NULL;
1584     uri_type url;
1585     uri_type proxy;
1586     uri_type *peer;
1587     parse_status_t status;
1588
1589     if( ( !url_str ) || ( !Handle ) || ( !contentType )
1590         || ( !httpStatus ) ) {
1591         return UPNP_E_INVALID_PARAM;
1592     }
1593
1594     ( *httpStatus ) = 0;
1595     ( *Handle ) = handle;
1596     ( *contentType ) = NULL;
1597     ( *contentLength ) = 0;
1598
1599     if( ( ret_code =
1600           MakeGetMessage( url_str, proxy_str, &request, &url ) ) != UPNP_E_SUCCESS ) {
1601         return ret_code;
1602     }
1603     if( proxy_str ) {
1604         ret_code = http_FixStrUrl( ( char * )proxy_str, strlen( proxy_str ), &proxy );
1605         peer = &proxy;
1606     } else {
1607         peer = &url;
1608     }
1609
1610     handle = ( http_get_handle_t * ) malloc( sizeof( http_get_handle_t ) );
1611
1612     if( handle == NULL ) {
1613         return UPNP_E_OUTOF_MEMORY;
1614     }
1615
1616     handle->entity_offset = 0;
1617     handle->cancel = 0;
1618     parser_response_init( &handle->response, HTTPMETHOD_GET );
1619
1620     tcp_connection = socket( AF_INET, SOCK_STREAM, 0 );
1621     if( tcp_connection == -1 ) {
1622         ret_code = UPNP_E_SOCKET_ERROR;
1623         goto errorHandler;
1624     }
1625
1626     if( sock_init( &handle->sock_info, tcp_connection ) != UPNP_E_SUCCESS )
1627     {
1628         sock_destroy( &handle->sock_info, SD_BOTH );
1629         ret_code = UPNP_E_SOCKET_ERROR;
1630         goto errorHandler;
1631     }
1632
1633     ret_code = connect( handle->sock_info.socket,
1634                         ( struct sockaddr * )&peer->hostport.IPv4address,
1635                         sizeof( struct sockaddr_in ) );
1636
1637     if( ret_code == -1 ) {
1638         sock_destroy( &handle->sock_info, SD_BOTH );
1639         ret_code = UPNP_E_SOCKET_CONNECT;
1640         goto errorHandler;
1641     }
1642     // send request
1643     ret_code = http_SendMessage( &handle->sock_info, &timeout, "b",
1644                                  request.buf, request.length );
1645     if( ret_code != 0 ) {
1646         sock_destroy( &handle->sock_info, SD_BOTH );
1647         goto errorHandler;
1648     }
1649
1650     status =
1651         ReadResponseLineAndHeaders( &handle->sock_info, &handle->response,
1652                                     &timeout, &http_error_code );
1653
1654     if( status != PARSE_OK ) {
1655         ret_code = UPNP_E_BAD_RESPONSE;
1656         goto errorHandler;
1657     }
1658
1659     status = parser_get_entity_read_method( &handle->response );
1660
1661     if( ( status != PARSE_CONTINUE_1 ) && ( status != PARSE_SUCCESS ) ) {
1662         ret_code = UPNP_E_BAD_RESPONSE;
1663         goto errorHandler;
1664     }
1665
1666     ( *httpStatus ) = handle->response.msg.status_code;
1667     ret_code = UPNP_E_SUCCESS;
1668
1669     if( httpmsg_find_hdr( &handle->response.msg, HDR_CONTENT_TYPE, &ctype )
1670         == NULL ) {
1671         *contentType = NULL;    // no content-type
1672     } else {
1673         *contentType = ctype.buf;
1674     }
1675
1676     if( handle->response.position == POS_COMPLETE ) {
1677         ( *contentLength ) = 0;
1678     } else if( handle->response.ent_position == ENTREAD_USING_CHUNKED ) {
1679         ( *contentLength ) = UPNP_USING_CHUNKED;
1680     } else if( handle->response.ent_position == ENTREAD_USING_CLEN ) {
1681         ( *contentLength ) = handle->response.content_length;
1682     } else if( handle->response.ent_position == ENTREAD_UNTIL_CLOSE ) {
1683         ( *contentLength ) = UPNP_UNTIL_CLOSE;
1684     }
1685
1686   errorHandler:
1687
1688     ( *Handle ) = handle;
1689
1690     membuffer_destroy( &request );
1691
1692     if( ret_code != UPNP_E_SUCCESS ) {
1693         httpmsg_destroy( &handle->response.msg );
1694     }
1695     return ret_code;
1696 }
1697
1698 /************************************************************************
1699  * Function: http_SendStatusResponse
1700  *
1701  * Parameters:
1702  *      IN SOCKINFO *info;              Socket information object
1703  *      IN int http_status_code;        error code returned while making 
1704  *                                      or sending the response message
1705  *      IN int request_major_version;   request major version
1706  *      IN int request_minor_version;   request minor version
1707  *
1708  * Description:
1709  *      Generate a response message for the status query and send the
1710  *      status response.
1711  *
1712  * Return: int
1713  *      0 -- success
1714  *      UPNP_E_OUTOF_MEMORY
1715  *      UPNP_E_SOCKET_WRITE
1716  *      UPNP_E_TIMEDOUT
1717  ************************************************************************/
1718 int
1719 http_SendStatusResponse( IN SOCKINFO * info,
1720                          IN int http_status_code,
1721                          IN int request_major_version,
1722                          IN int request_minor_version )
1723 {
1724     int response_major,
1725       response_minor;
1726     membuffer membuf;
1727     int ret;
1728     int timeout;
1729
1730     http_CalcResponseVersion( request_major_version, request_minor_version,
1731                               &response_major, &response_minor );
1732
1733     membuffer_init( &membuf );
1734     membuf.size_inc = 70;
1735
1736     ret = http_MakeMessage(
1737         &membuf, response_major, response_minor,
1738         "RSCB",
1739         http_status_code,  // response start line
1740         http_status_code ); // body
1741     if( ret == 0 ) {
1742         timeout = HTTP_DEFAULT_TIMEOUT;
1743         ret = http_SendMessage( info, &timeout, "b",
1744                                 membuf.buf, membuf.length );
1745     }
1746
1747     membuffer_destroy( &membuf );
1748
1749     return ret;
1750 }
1751
1752
1753 /************************************************************************
1754  * Function: http_MakeMessage
1755  *
1756  * Parameters:
1757  *      INOUT membuffer* buf;           buffer with the contents of the 
1758  *                                      message
1759  *      IN int http_major_version;      HTTP major version
1760  *      IN int http_minor_version;      HTTP minor version
1761  *      IN const char* fmt;             Pattern format 
1762  *      ...;    
1763  *
1764  * Description:
1765  *      Generate an HTTP message based on the format that is specified
1766  *      in the input parameters.
1767  *
1768  * fmt types:
1769  *      'B':    arg = int status_code 
1770  *              appends content-length, content-type and HTML body
1771  *              for given code
1772  *      'b':    arg1 = const char* buf;
1773  *              arg2 = size_t buf_length memory ptr
1774  *      'C':    (no args) appends a HTTP CONNECTION: close header 
1775  *                      depending on major,minor version
1776  *      'c':    (no args) appends CRLF "\r\n"
1777  *      'D':    (no args) appends HTTP DATE: header
1778  *      'd':    arg = int number            // appends decimal number
1779  *      'G':    arg = range information     // add range header
1780  *      'h':    arg = off_t number          // appends off_t number
1781  *      'K':    (no args)                   // add chunky header
1782  *      'N':    arg1 = off_t content_length // content-length header
1783  *      'q':    arg1 = http_method_t        // request start line and HOST header
1784  *              arg2 = (uri_type *)
1785  *      'Q':    arg1 = http_method_t;       // start line of request
1786  *              arg2 = char* url; 
1787  *              arg3 = size_t url_length 
1788  *      'R':    arg = int status_code       // adds a response start line
1789  *      'S':    (no args) appends HTTP SERVER: header
1790  *      's':    arg = const char* C_string
1791  *      'T':    arg = char * content_type; format
1792  *              e.g: "text/html"; content-type header
1793  *      't':    arg = time_t * gmt_time     // appends time in RFC 1123 fmt
1794  *      'U':    (no args) appends HTTP USER-AGENT: header
1795  *      'X':    arg = const char useragent; "redsonic" HTTP X-User-Agent: useragent
1796  *
1797  * Return: int
1798  *      0 - On Success
1799  *      UPNP_E_OUTOF_MEMORY
1800  *      UPNP_E_INVALID_URL
1801  ************************************************************************/
1802 int
1803 http_MakeMessage( INOUT membuffer * buf,
1804                   IN int http_major_version,
1805                   IN int http_minor_version,
1806                   IN const char *fmt,
1807                   ... )
1808 {
1809     char c;
1810     char *s = NULL;
1811     size_t num;
1812     off_t bignum;
1813     size_t length;
1814     time_t *loc_time;
1815     time_t curr_time;
1816     struct tm *date;
1817     char *start_str,
1818      *end_str;
1819     int status_code;
1820     const char *status_msg;
1821     http_method_t method;
1822     const char *method_str;
1823     const char *url_str;
1824     const char *temp_str;
1825     uri_type url;
1826     uri_type *uri_ptr;
1827     int error_code = UPNP_E_OUTOF_MEMORY;
1828
1829     va_list argp;
1830     char tempbuf[200];
1831     const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
1832     const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
1833         "Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
1834
1835     va_start( argp, fmt );
1836
1837     while( ( c = *fmt++ ) != 0 ) {
1838         if( c == 's' ) {
1839             // C string
1840             s = ( char * )va_arg( argp, char * );
1841             assert( s );
1842             UpnpPrintf(UPNP_ALL,HTTP,__FILE__,__LINE__,"Adding a string : %s\n", s); 
1843             if( membuffer_append( buf, s, strlen( s ) ) != 0 ) {
1844                 goto error_handler;
1845             }
1846         } else if( c == 'K' ) {
1847             // Add Chunky header
1848             if( membuffer_append
1849                 ( buf, "TRANSFER-ENCODING: chunked\r\n",
1850                   strlen( "Transfer-Encoding: chunked\r\n" ) ) != 0 ) {
1851                 goto error_handler;
1852             }
1853         } else if( c == 'G' ) {
1854             // Add Range header
1855             struct SendInstruction *RespInstr;
1856             RespInstr = (struct SendInstruction *)
1857                 va_arg( argp, struct SendInstruction *);
1858             assert( RespInstr );
1859             // connection header
1860             if( membuffer_append
1861                 ( buf, RespInstr->RangeHeader,
1862                   strlen( RespInstr->RangeHeader ) ) != 0 ) {
1863                 goto error_handler;
1864             }
1865         } else if( c == 'b' ) {
1866             // mem buffer
1867             s = ( char * )va_arg( argp, char * );
1868
1869             UpnpPrintf(UPNP_ALL,HTTP,__FILE__,__LINE__,
1870                 "Adding a char Buffer starting with: %c\n", s[0]);
1871             assert( s );
1872             length = ( size_t ) va_arg( argp, size_t );
1873             if( membuffer_append( buf, s, length ) != 0 ) {
1874                 goto error_handler;
1875             }
1876         }
1877         else if( c == 'c' ) {
1878             // crlf
1879             if( membuffer_append( buf, "\r\n", 2 ) != 0 ) {
1880                 goto error_handler;
1881             }
1882         }
1883         else if( c == 'd' ) {
1884             // integer
1885             num = ( int )va_arg( argp, int );
1886             sprintf( tempbuf, "%"PRIzu, num );
1887             if( membuffer_append( buf, tempbuf, strlen( tempbuf ) ) != 0 ) {
1888                 goto error_handler;
1889             }
1890         }
1891         else if( c == 'h' ) {
1892             // off_t
1893             bignum = ( off_t )va_arg( argp, off_t );
1894
1895             sprintf( tempbuf, "%"PRId64, (int64_t)bignum );
1896             if( membuffer_append( buf, tempbuf, strlen( tempbuf ) ) != 0 ) {
1897                 goto error_handler;
1898             }
1899         }
1900         else if( c == 't' || c == 'D' ) {
1901             // date
1902             if( c == 'D' ) {
1903                 // header
1904                 start_str = "DATE: ";
1905                 end_str = "\r\n";
1906                 curr_time = time( NULL );
1907                 date = gmtime( &curr_time );
1908             } else {
1909                 // date value only
1910                 start_str = end_str = "";
1911                 loc_time = ( time_t * ) va_arg( argp, time_t * );
1912                 assert( loc_time );
1913                 date = gmtime( loc_time );
1914             }
1915
1916             sprintf( tempbuf, "%s%s, %02d %s %d %02d:%02d:%02d GMT%s",
1917                      start_str,
1918                      &weekday_str[date->tm_wday * 4], date->tm_mday,
1919                      &month_str[date->tm_mon * 4], date->tm_year + 1900,
1920                      date->tm_hour, date->tm_min, date->tm_sec, end_str );
1921
1922             if( membuffer_append( buf, tempbuf, strlen( tempbuf ) ) != 0 ) {
1923                 goto error_handler;
1924             }
1925         } else if( c == 'C' ) {
1926             if( ( http_major_version > 1 ) ||
1927                 ( http_major_version == 1 && http_minor_version == 1 )
1928                  ) {
1929                 // connection header
1930                 if( membuffer_append_str( buf, "CONNECTION: close\r\n" ) !=
1931                     0 ) {
1932                     goto error_handler;
1933                 }
1934             }
1935         } else if( c == 'N' ) {
1936             // content-length header
1937             bignum = ( off_t )va_arg( argp, off_t );
1938
1939             assert( bignum >= 0 );
1940             if (http_MakeMessage(
1941                 buf, http_major_version, http_minor_version,
1942                 "shc",
1943                 "CONTENT-LENGTH: ", bignum ) != 0 ) {
1944                 goto error_handler;
1945             }
1946         } else if( c == 'S' || c == 'U' ) {
1947             // SERVER or USER-AGENT header
1948             temp_str = ( c == 'S' ) ? "SERVER: " : "USER-AGENT: ";
1949             get_sdk_info( tempbuf );
1950             if (http_MakeMessage(
1951                 buf, http_major_version, http_minor_version,
1952                 "ss",
1953                 temp_str, tempbuf ) != 0 ) {
1954                 goto error_handler;
1955             }
1956         } else if( c == 'X' ) {
1957             // C string
1958             s = ( char * )va_arg( argp, char * );
1959             assert( s );
1960             if( membuffer_append_str( buf, "X-User-Agent: ") != 0 ) {
1961                 goto error_handler;
1962             }
1963             if( membuffer_append( buf, s, strlen( s ) ) != 0 ) {
1964                 goto error_handler;
1965             }
1966         } else if( c == 'R' ) {
1967             // response start line
1968             //   e.g.: 'HTTP/1.1 200 OK'
1969             //
1970             // code
1971             status_code = ( int )va_arg( argp, int );
1972             assert( status_code > 0 );
1973             sprintf( tempbuf, "HTTP/%d.%d %d ",
1974                      http_major_version, http_minor_version, status_code );
1975             // str
1976             status_msg = http_get_code_text( status_code );
1977             if (http_MakeMessage(
1978                 buf, http_major_version, http_minor_version,
1979                 "ssc",
1980                 tempbuf,
1981                 status_msg ) != 0 ) {
1982                 goto error_handler;
1983             }
1984         } else if( c == 'B' ) {
1985             // body of a simple reply
1986             // 
1987             status_code = ( int )va_arg( argp, int );
1988             sprintf( tempbuf, "%s%d %s%s",
1989                      "<html><body><h1>",
1990                      status_code, http_get_code_text( status_code ),
1991                      "</h1></body></html>" );
1992             bignum = strlen( tempbuf );
1993             if (http_MakeMessage(
1994                     buf, http_major_version, http_minor_version,
1995                     "NTcs",
1996                     bignum, // content-length
1997                     "text/html",  // content-type
1998                     tempbuf ) != 0 // body
1999             ) {
2000                 goto error_handler;
2001             }
2002         } else if( c == 'Q' ) {
2003             // request start line
2004             // GET /foo/bar.html HTTP/1.1\r\n
2005             method = ( http_method_t ) va_arg( argp, http_method_t );
2006             method_str = method_to_str( method );
2007             url_str = ( const char * )va_arg( argp, const char * );
2008             num = ( size_t )va_arg( argp, size_t );   // length of url_str
2009             if (http_MakeMessage(
2010                 buf, http_major_version, http_minor_version,
2011                 "ssbsdsdc",
2012                 method_str,  // method
2013                 " ", url_str, num,    // url
2014                 " HTTP/", http_major_version, ".", http_minor_version ) != 0 ) {
2015                 goto error_handler;
2016             }
2017         } else if( c == 'q' ) {
2018             // request start line and HOST header
2019             method = ( http_method_t ) va_arg( argp, http_method_t );
2020             uri_ptr = ( uri_type * ) va_arg( argp, uri_type * );
2021             assert( uri_ptr );
2022             if( http_FixUrl( uri_ptr, &url ) != 0 ) {
2023                 error_code = UPNP_E_INVALID_URL;
2024                 goto error_handler;
2025             }
2026             if (http_MakeMessage(
2027                 buf, http_major_version, http_minor_version,
2028                 "Q" "sbc",
2029                 method, url.pathquery.buff, url.pathquery.size,
2030                 "HOST: ", url.hostport.text.buff, url.hostport.text.size ) != 0 ) {
2031                 goto error_handler;
2032             }
2033         } else if( c == 'T' ) {
2034             // content type header
2035             temp_str = ( const char * )va_arg( argp, const char * );    // type/subtype format
2036             if (http_MakeMessage(
2037                 buf, http_major_version, http_minor_version,
2038                 "ssc",
2039                 "CONTENT-TYPE: ", temp_str ) != 0 ) {
2040                 goto error_handler;
2041             }
2042         } else {
2043             assert( 0 );
2044         }
2045     }
2046
2047     return 0;
2048
2049 error_handler:
2050     va_end( argp );
2051     membuffer_destroy( buf );
2052     return error_code;
2053 }
2054
2055
2056 /************************************************************************
2057  * Function: http_CalcResponseVersion
2058  *
2059  * Parameters:
2060  *      IN int request_major_vers;      Request major version
2061  *      IN int request_minor_vers;      Request minor version
2062  *      OUT int* response_major_vers;   Response mojor version
2063  *      OUT int* response_minor_vers;   Response minor version
2064  *
2065  * Description:
2066  *      Calculate HTTP response versions based on the request versions.
2067  *
2068  * Return: void
2069  ************************************************************************/
2070 void
2071 http_CalcResponseVersion( IN int request_major_vers,
2072                           IN int request_minor_vers,
2073                           OUT int *response_major_vers,
2074                           OUT int *response_minor_vers )
2075 {
2076     if( ( request_major_vers > 1 ) ||
2077         ( request_major_vers == 1 && request_minor_vers >= 1 )
2078          ) {
2079         *response_major_vers = 1;
2080         *response_minor_vers = 1;
2081     } else {
2082         *response_major_vers = request_major_vers;
2083         *response_minor_vers = request_minor_vers;
2084     }
2085 }
2086
2087 /************************************************************************
2088 * Function: MakeGetMessageEx
2089 *
2090 * Parameters:
2091 *       const char *url_str;    String as a URL
2092 *       membuffer *request;     Buffer containing the request
2093 *       uri_type *url;          URI object containing the scheme, path
2094 *                               query token, etc.
2095 *
2096 * Description:
2097 *       Makes the message for the HTTP GET method
2098 *
2099 * Returns:
2100 *       UPNP_E_INVALID_URL
2101 *       Error Codes returned by http_MakeMessage
2102 *       UPNP_E_SUCCESS
2103 ************************************************************************/
2104 int
2105 MakeGetMessageEx( const char *url_str,
2106                   membuffer * request,
2107                   uri_type * url,
2108                   struct SendInstruction *pRangeSpecifier )
2109 {
2110     int errCode = UPNP_E_SUCCESS;
2111     char *urlPath = NULL;
2112     size_t hostlen = 0;
2113     char *hoststr,
2114      *temp;
2115
2116     do {
2117         UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
2118             "DOWNLOAD URL : %s\n", url_str );
2119
2120         if( ( errCode = http_FixStrUrl( ( char * )url_str,
2121             strlen( url_str ), url ) ) != UPNP_E_SUCCESS ) {
2122             break;
2123         }
2124         // make msg
2125         membuffer_init( request );
2126         urlPath = alloca( strlen( url_str ) + 1 );
2127         if( !urlPath ) {
2128             errCode = UPNP_E_OUTOF_MEMORY;
2129             break;
2130         }
2131
2132         memset( urlPath, 0, strlen( url_str ) + 1 );
2133         strcpy( urlPath, url_str );
2134         hoststr = strstr( urlPath, "//" );
2135         if( hoststr == NULL ) {
2136             errCode = UPNP_E_INVALID_URL;
2137             break;
2138         }
2139
2140         hoststr += 2;
2141         temp = strchr( hoststr, '/' );
2142         if( temp == NULL ) {
2143             errCode = UPNP_E_INVALID_URL;
2144             break;
2145         }
2146
2147         *temp = '\0';
2148         hostlen = strlen( hoststr );
2149         *temp = '/';
2150         UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
2151             "HOSTNAME : %s Length : %"PRIzu"\n",
2152             hoststr, hostlen );
2153
2154         errCode = http_MakeMessage(
2155                 request, 1, 1,
2156                 "Q" "s" "bc" "GDCUc",
2157                 HTTPMETHOD_GET, url->pathquery.buff, url->pathquery.size,
2158                 "HOST: ",
2159                 hoststr, hostlen,
2160                 pRangeSpecifier );
2161
2162         if( errCode != 0 ) {
2163             UpnpPrintf( UPNP_INFO, HTTP, __FILE__, __LINE__,
2164                 "HTTP Makemessage failed\n" );
2165             membuffer_destroy( request );
2166
2167             return errCode;
2168         }
2169     } while( 0 );
2170
2171     UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
2172         "HTTP Buffer:\n%s\n" "----------END--------\n",
2173         request->buf);
2174
2175     return errCode;
2176 }
2177
2178 #define SIZE_RANGE_BUFFER 50
2179
2180 /************************************************************************
2181  * Function: http_OpenHttpGetEx
2182  *
2183  * Parameters:
2184  *      IN const char *url_str;         String as a URL
2185  *      IN OUT void **Handle;           Pointer to buffer to store HTTP
2186  *                                      post handle
2187  *      IN OUT char **contentType;      Type of content
2188  *      OUT int *contentLength;         length of content
2189  *      OUT int *httpStatus;            HTTP status returned on receiving a
2190  *                                      response message
2191  *      IN int timeout;                 time out value
2192  *
2193  * Description:
2194  *      Makes the HTTP GET message, connects to the peer, 
2195  *      sends the HTTP GET request, gets the response and parses the 
2196  *      response.
2197  *
2198  * Return: int
2199  *      UPNP_E_SUCCESS          - On Success
2200  *      UPNP_E_INVALID_PARAM    - Invalid Paramters
2201  *      UPNP_E_OUTOF_MEMORY
2202  *      UPNP_E_SOCKET_ERROR
2203  *      UPNP_E_BAD_RESPONSE
2204  ************************************************************************/
2205 int
2206 http_OpenHttpGetEx( IN const char *url_str,
2207                     IN OUT void **Handle,
2208                     IN OUT char **contentType,
2209                     OUT int *contentLength,
2210                     OUT int *httpStatus,
2211                     IN int lowRange,
2212                     IN int highRange,
2213                     IN int timeout )
2214 {
2215     int http_error_code;
2216     memptr ctype;
2217     int tcp_connection;
2218     membuffer request;
2219     http_get_handle_t *handle = NULL;
2220     uri_type url;
2221     parse_status_t status;
2222     int errCode = UPNP_E_SUCCESS;
2223
2224     //  char rangeBuf[SIZE_RANGE_BUFFER];
2225     struct SendInstruction rangeBuf;
2226
2227     do {
2228         // Checking Input parameters
2229         if( ( !url_str ) || ( !Handle ) ||