David Balazic pointed out the lack of checks for a valid %XX code when
[platform/upstream/curl.git] / lib / http.c
1 /***************************************************************************
2  *                                  _   _ ____  _     
3  *  Project                     ___| | | |  _ \| |    
4  *                             / __| | | | |_) | |    
5  *                            | (__| |_| |  _ <| |___ 
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  * 
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #ifndef CURL_DISABLE_HTTP
27 /* -- WIN32 approved -- */
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include <errno.h>
37
38 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
39 #include <winsock.h>
40 #include <time.h>
41 #include <io.h>
42 #else
43 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 #include <netinet/in.h>
48 #endif
49 #include <sys/time.h>
50
51 #ifdef HAVE_TIME_H
52 #ifdef TIME_WITH_SYS_TIME
53 #include <time.h>
54 #endif
55 #endif
56
57 #include <sys/resource.h>
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #include <netdb.h>
62 #ifdef HAVE_ARPA_INET_H
63 #include <arpa/inet.h>
64 #endif
65 #ifdef HAVE_NET_IF_H
66 #include <net/if.h>
67 #endif
68 #include <sys/ioctl.h>
69 #include <signal.h>
70
71 #ifdef HAVE_SYS_PARAM_H
72 #include <sys/param.h>
73 #endif
74
75 #ifdef HAVE_SYS_SELECT_H
76 #include <sys/select.h>
77 #endif
78
79
80 #endif
81
82 #include "urldata.h"
83 #include <curl/curl.h>
84 #include "transfer.h"
85 #include "sendf.h"
86 #include "formdata.h"
87 #include "progress.h"
88 #include "base64.h"
89 #include "cookie.h"
90 #include "strequal.h"
91 #include "ssluse.h"
92
93 #define _MPRINTF_REPLACE /* use our functions only */
94 #include <curl/mprintf.h>
95
96 /* The last #include file should be: */
97 #ifdef MALLOCDEBUG
98 #include "memdebug.h"
99 #endif
100
101 /* fread() emulation to provide POST and/or request data */
102 static int readmoredata(char *buffer,
103                         size_t size,
104                         size_t nitems,
105                         void *userp)
106 {
107   struct connectdata *conn = (struct connectdata *)userp;
108   struct HTTP *http = conn->proto.http;
109   int fullsize = size * nitems;
110
111   if(0 == http->postsize)
112     /* nothing to return */
113     return 0;
114   
115   /* make sure that a HTTP request is never sent away chunked! */
116   conn->bits.forbidchunk= (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
117
118   if(http->postsize <= fullsize) {
119     memcpy(buffer, http->postdata, http->postsize);
120     fullsize = http->postsize;
121
122     if(http->backup.postsize) {
123       /* move backup data into focus and continue on that */
124       http->postdata = http->backup.postdata;
125       http->postsize = http->backup.postsize;
126       conn->fread =    http->backup.fread;
127       conn->fread_in = http->backup.fread_in;
128
129       http->sending++; /* move one step up */
130
131       http->backup.postsize=0;
132     }
133     else
134       http->postsize = 0;
135
136     return fullsize;
137   }
138
139   memcpy(buffer, http->postdata, fullsize);
140   http->postdata += fullsize;
141   http->postsize -= fullsize;
142
143   return fullsize;
144 }
145
146 /* ------------------------------------------------------------------------- */
147 /*
148  * The add_buffer series of functions are used to build one large memory chunk
149  * from repeated function invokes. Used so that the entire HTTP request can
150  * be sent in one go.
151  */
152
153 struct send_buffer {
154   char *buffer;
155   size_t size_max;
156   size_t size_used;
157 };
158 typedef struct send_buffer send_buffer;
159
160 static CURLcode
161  add_buffer(send_buffer *in, const void *inptr, size_t size);
162
163 /*
164  * add_buffer_init() returns a fine buffer struct
165  */
166 static
167 send_buffer *add_buffer_init(void)
168 {
169   send_buffer *blonk;
170   blonk=(send_buffer *)malloc(sizeof(send_buffer));
171   if(blonk) {
172     memset(blonk, 0, sizeof(send_buffer));
173     return blonk;
174   }
175   return NULL; /* failed, go home */
176 }
177
178 /*
179  * add_buffer_send() sends a buffer and frees all associated memory.
180  */
181 static
182 CURLcode add_buffer_send(send_buffer *in,
183                          int sockfd,
184                          struct connectdata *conn,
185                          long *bytes_written) /* add the number of sent
186                                                  bytes to this counter */
187 {
188   ssize_t amount;
189   CURLcode res;
190   char *ptr;
191   int size;
192   struct HTTP *http = conn->proto.http;
193
194   /* The looping below is required since we use non-blocking sockets, but due
195      to the circumstances we will just loop and try again and again etc */
196
197   ptr = in->buffer;
198   size = in->size_used;
199
200   res = Curl_write(conn, sockfd, ptr, size, &amount);
201
202   if(CURLE_OK == res) {
203
204     if(conn->data->set.verbose)
205       /* this data _may_ contain binary stuff */
206       Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount);
207
208     *bytes_written += amount;
209     
210     if(amount != size) {
211       /* The whole request could not be sent in one system call. We must queue
212          it up and send it later when we get the chance. We must not loop here
213          and wait until it might work again. */
214
215       size -= amount;
216       ptr += amount;
217     
218       /* backup the currently set pointers */
219       http->backup.fread = conn->fread;
220       http->backup.fread_in = conn->fread_in;
221       http->backup.postdata = http->postdata;
222       http->backup.postsize = http->postsize;
223
224       /* set the new pointers for the request-sending */
225       conn->fread = (curl_read_callback)readmoredata;
226       conn->fread_in = (void *)conn;
227       http->postdata = ptr;
228       http->postsize = size;
229
230       http->send_buffer = in;
231       http->sending = HTTPSEND_REQUEST;
232       
233       return CURLE_OK;
234     }
235     http->sending = HTTPSEND_BODY;
236     /* the full buffer was sent, clean up and return */
237   }
238   if(in->buffer)
239     free(in->buffer);
240   free(in);
241
242   return res;
243 }
244
245
246 /* 
247  * add_bufferf() builds a buffer from the formatted input
248  */
249 static
250 CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
251 {
252   CURLcode result = CURLE_OUT_OF_MEMORY;
253   char *s;
254   va_list ap;
255   va_start(ap, fmt);
256   s = vaprintf(fmt, ap); /* this allocs a new string to append */
257   va_end(ap);
258
259   if(s) {
260     result = add_buffer(in, s, strlen(s));
261     free(s);
262   }
263   return result;
264 }
265
266 /*
267  * add_buffer() appends a memory chunk to the existing one
268  */
269 static
270 CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
271 {
272   char *new_rb;
273   int new_size;
274
275   if(!in->buffer ||
276      ((in->size_used + size) > (in->size_max - 1))) {
277     new_size = (in->size_used+size)*2;
278     if(in->buffer)
279       /* we have a buffer, enlarge the existing one */
280       new_rb = (char *)realloc(in->buffer, new_size);
281     else
282       /* create a new buffer */
283       new_rb = (char *)malloc(new_size);
284
285     if(!new_rb)
286       return CURLE_OUT_OF_MEMORY;
287
288     in->buffer = new_rb;
289     in->size_max = new_size;
290   }
291   memcpy(&in->buffer[in->size_used], inptr, size);
292       
293   in->size_used += size;
294
295   return CURLE_OK;
296 }
297
298 /* end of the add_buffer functions */
299 /* ------------------------------------------------------------------------- */
300
301 /*
302  * Curl_compareheader()
303  *
304  * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
305  * Pass headers WITH the colon.
306  */
307 bool
308 Curl_compareheader(char *headerline,    /* line to check */
309                    const char *header,  /* header keyword _with_ colon */
310                    const char *content) /* content string to find */
311 {
312   /* RFC2616, section 4.2 says: "Each header field consists of a name followed
313    * by a colon (":") and the field value. Field names are case-insensitive.
314    * The field value MAY be preceded by any amount of LWS, though a single SP
315    * is preferred." */
316
317   size_t hlen = strlen(header);
318   size_t clen;
319   size_t len;
320   char *start;
321   char *end;
322
323   if(!strnequal(headerline, header, hlen))
324     return FALSE; /* doesn't start with header */
325
326   /* pass the header */
327   start = &headerline[hlen];
328
329   /* pass all white spaces */
330   while(*start && isspace((int)*start))
331     start++;
332
333   /* find the end of the header line */
334   end = strchr(start, '\r'); /* lines end with CRLF */
335   if(!end) {
336     /* in case there's a non-standard compliant line here */
337     end = strchr(start, '\n');
338
339     if(!end)
340       /* hm, there's no line ending here, use the zero byte! */
341       end = strchr(start, '\0');
342   }
343
344   len = end-start; /* length of the content part of the input line */
345   clen = strlen(content); /* length of the word to find */
346
347   /* find the content string in the rest of the line */
348   for(;len>=clen;len--, start++) {
349     if(strnequal(start, content, clen))
350       return TRUE; /* match! */
351   }
352
353   return FALSE; /* no match */
354 }
355
356 /*
357  * This function checks the linked list of custom HTTP headers for a particular
358  * header (prefix).
359  */
360 static char *checkheaders(struct SessionHandle *data, const char *thisheader)
361 {
362   struct curl_slist *head;
363   size_t thislen = strlen(thisheader);
364
365   for(head = data->set.headers; head; head=head->next) {
366     if(strnequal(head->data, thisheader, thislen))
367       return head->data;
368   }
369   return NULL;
370 }
371
372 /*
373  * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
374  * function will issue the necessary commands to get a seamless tunnel through
375  * this proxy. After that, the socket can be used just as a normal socket.
376  */
377
378 CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
379                                      int tunnelsocket,
380                                      char *hostname, int remote_port)
381 {
382   int httperror=0;
383   int subversion=0;
384   struct SessionHandle *data=conn->data;
385   CURLcode result;
386   int res;
387
388   int nread;   /* total size read */
389   int perline; /* count bytes per line */
390   bool keepon=TRUE;
391   ssize_t gotbytes;
392   char *ptr;
393   int timeout = 3600; /* default timeout in seconds */
394   struct timeval interval;
395   fd_set rkeepfd;
396   fd_set readfd;
397   char *line_start;
398
399 #define SELECT_OK      0
400 #define SELECT_ERROR   1
401 #define SELECT_TIMEOUT 2
402   int error = SELECT_OK;
403
404   infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
405
406   /* OK, now send the connect request to the proxy */
407   result =
408     Curl_sendf(tunnelsocket, conn,
409                "CONNECT %s:%d HTTP/1.0\015\012"
410                "%s"
411                "%s"
412                "\r\n",
413                hostname, remote_port,
414                (conn->bits.proxy_user_passwd)?conn->allocptr.proxyuserpwd:"",
415                (data->set.useragent?conn->allocptr.uagent:"")
416                );
417   if(result) {
418     failf(data, "Failed sending CONNECT to proxy");
419     return result;
420   }
421
422   /* Now, read the full reply we get from the proxy */
423
424
425   if(data->set.timeout) {
426     /* if timeout is requested, find out how much remaining time we have */
427     timeout = data->set.timeout - /* timeout time */
428       Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
429     if(timeout <=0 ) {
430       failf(data, "Transfer aborted due to timeout");
431       return -SELECT_TIMEOUT; /* already too little time */
432     }
433   }
434
435   FD_ZERO (&readfd);            /* clear it */
436   FD_SET (tunnelsocket, &readfd);     /* read socket */
437
438   /* get this in a backup variable to be able to restore it on each lap in the
439      select() loop */
440   rkeepfd = readfd;
441
442   ptr=data->state.buffer;
443   line_start = ptr;
444
445   nread=0;
446   perline=0;
447   keepon=TRUE;
448
449   while((nread<BUFSIZE) && (keepon && !error)) {
450     readfd = rkeepfd;              /* set every lap */
451     interval.tv_sec = timeout;
452     interval.tv_usec = 0;
453
454     switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
455     case -1: /* select() error, stop reading */
456       error = SELECT_ERROR;
457       failf(data, "Transfer aborted due to select() error");
458       break;
459     case 0: /* timeout */
460       error = SELECT_TIMEOUT;
461       failf(data, "Transfer aborted due to timeout");
462       break;
463     default:
464       /*
465        * This code previously didn't use the kerberos sec_read() code
466        * to read, but when we use Curl_read() it may do so. Do confirm
467        * that this is still ok and then remove this comment!
468        */
469       res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
470                      &gotbytes);
471       if(res< 0)
472         /* EWOULDBLOCK */
473         continue; /* go loop yourself */
474       else if(res)
475         keepon = FALSE;
476       else if(gotbytes <= 0) {
477         keepon = FALSE;
478         error = SELECT_ERROR;
479         failf(data, "Connection aborted");
480       }
481       else {
482         /* we got a whole chunk of data, which can be anything from one
483          * byte to a set of lines and possibly just a piece of the last
484          * line */
485         int i;
486
487         nread += gotbytes;
488         for(i = 0; i < gotbytes; ptr++, i++) {
489           perline++; /* amount of bytes in this line so far */
490           if(*ptr=='\n') {
491             /* a newline is CRLF in ftp-talk, so the CR is ignored as
492                the line isn't really terminated until the LF comes */
493
494             if('\r' == line_start[0]) {
495               /* end of headers */
496               keepon=FALSE;
497               break; /* breaks out of loop, not switch */
498             }
499
500             /* output debug output if that is requested */
501             if(data->set.verbose)
502               Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
503
504             if(2 == sscanf(line_start, "HTTP/1.%d %d",
505                            &subversion,
506                            &httperror)) {
507               ;
508             }
509
510             perline=0; /* line starts over here */
511             line_start = ptr+1;
512           }
513         }
514       }
515       break;
516     } /* switch */
517   } /* while there's buffer left and loop is requested */
518
519   if(error)
520     return CURLE_RECV_ERROR;
521
522   if(200 != httperror) {
523     if(407 == httperror)
524       /* Added Nov 6 1998 */
525       failf(data, "Proxy requires authorization!");
526     else 
527       failf(data, "Received error code %d from proxy", httperror);
528     return CURLE_RECV_ERROR;
529   }
530
531   infof (data, "Proxy replied to CONNECT request\n");
532   return CURLE_OK;
533 }
534
535 /*
536  * HTTP stuff to do at connect-time.
537  */
538 CURLcode Curl_http_connect(struct connectdata *conn)
539 {
540   struct SessionHandle *data;
541   CURLcode result;
542
543   data=conn->data;
544
545   /* If we are not using a proxy and we want a secure connection,
546    * perform SSL initialization & connection now.
547    * If using a proxy with https, then we must tell the proxy to CONNECT
548    * us to the host we want to talk to.  Only after the connect
549    * has occured, can we start talking SSL
550    */
551
552   if(conn->bits.httpproxy &&
553      ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {
554
555     /* either HTTPS over proxy, OR explicitly asked for a tunnel */
556     result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket,
557                                          conn->hostname, conn->remote_port);
558     if(CURLE_OK != result)
559       return result;
560   }    
561
562   if(conn->protocol & PROT_HTTPS) {
563     /* now, perform the SSL initialization for this socket */
564     result = Curl_SSLConnect(conn);
565     if(result)
566       return result;
567   }
568
569   if(conn->bits.user_passwd && !data->state.this_is_a_follow) {
570     /* Authorization: is requested, this is not a followed location, get the
571        original host name */
572     if (data->state.auth_host)
573       /* Free to avoid leaking memory on multiple requests*/
574       free(data->state.auth_host);
575
576     data->state.auth_host = strdup(conn->hostname);
577   }
578
579   return CURLE_OK;
580 }
581
582 CURLcode Curl_http_done(struct connectdata *conn)
583 {
584   struct SessionHandle *data;
585   struct HTTP *http;
586
587   data=conn->data;
588   http=conn->proto.http;
589
590   /* set the proper values (possibly modified on POST) */
591   conn->fread = data->set.fread; /* restore */
592   conn->fread_in = data->set.in; /* restore */
593
594   if(http->send_buffer) {
595     send_buffer *buff = http->send_buffer;
596     
597     free(buff->buffer);
598     free(buff);
599   }
600
601   if(HTTPREQ_POST_FORM == data->set.httpreq) {
602     conn->bytecount = http->readbytecount + http->writebytecount;
603       
604     Curl_formclean(http->sendit); /* Now free that whole lot */
605   }
606   else if(HTTPREQ_PUT == data->set.httpreq)
607     conn->bytecount = http->readbytecount + http->writebytecount;
608
609   if(0 == (http->readbytecount + conn->headerbytecount)) {
610     /* nothing was read from the HTTP server, this can't be right
611        so we return an error here */
612     failf(data, "Empty reply from server");
613     return CURLE_GOT_NOTHING;
614   }
615
616   return CURLE_OK;
617 }
618
619 CURLcode Curl_http(struct connectdata *conn)
620 {
621   struct SessionHandle *data=conn->data;
622   char *buf = data->state.buffer; /* this is a short cut to the buffer */
623   CURLcode result=CURLE_OK;
624   struct HTTP *http;
625   struct Cookie *co=NULL; /* no cookies from start */
626   char *ppath = conn->ppath; /* three previous function arguments */
627   char *host = conn->name;
628   const char *te = ""; /* tranfer-encoding */
629   char *ptr;
630
631   if(!conn->proto.http) {
632     /* Only allocate this struct if we don't already have it! */
633
634     http = (struct HTTP *)malloc(sizeof(struct HTTP));
635     if(!http)
636       return CURLE_OUT_OF_MEMORY;
637     memset(http, 0, sizeof(struct HTTP));
638     conn->proto.http = http;
639   }
640   else
641     http = conn->proto.http;
642
643   /* We default to persistant connections */
644   conn->bits.close = FALSE;
645
646   if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
647        data->set.upload) {
648     data->set.httpreq = HTTPREQ_PUT;
649   }
650   
651   /* The User-Agent string has been built in url.c already, because it might
652      have been used in the proxy connect, but if we have got a header with
653      the user-agent string specified, we erase the previously made string
654      here. */
655   if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
656     free(conn->allocptr.uagent);
657     conn->allocptr.uagent=NULL;
658   }
659
660   if((conn->bits.user_passwd) && !checkheaders(data, "Authorization:")) {
661     char *authorization;
662
663     /* To prevent the user+password to get sent to other than the original
664        host due to a location-follow, we do some weirdo checks here */
665     if(!data->state.this_is_a_follow ||
666        !data->state.auth_host ||
667        curl_strequal(data->state.auth_host, conn->hostname) ||
668        data->set.http_disable_hostname_check_before_authentication) {
669       sprintf(data->state.buffer, "%s:%s",
670               data->state.user, data->state.passwd);
671       if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
672                             &authorization) >= 0) {
673         if(conn->allocptr.userpwd)
674           free(conn->allocptr.userpwd);
675         conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012",
676                                           authorization);
677         free(authorization);
678       }
679     }
680   }
681   if((data->change.referer) && !checkheaders(data, "Referer:")) {
682     if(conn->allocptr.ref)
683       free(conn->allocptr.ref);
684     conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
685   }
686   if(data->set.cookie && !checkheaders(data, "Cookie:")) {
687     if(conn->allocptr.cookie)
688       free(conn->allocptr.cookie);
689     conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
690   }
691
692   if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
693     /* not a chunky transfer but data is to be sent */
694     char *ptr = checkheaders(data, "Transfer-Encoding:");
695     if(ptr) {
696       /* Some kind of TE is requested, check if 'chunked' is chosen */
697       if(Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"))
698         /* we have been told explicitly to upload chunky so deal with it! */
699         conn->bits.upload_chunky = TRUE;
700     }
701   }
702
703   if(conn->bits.upload_chunky) {
704     /* RFC2616 section 4.4:
705        Messages MUST NOT include both a Content-Length header field and a
706        non-identity transfer-coding. If the message does include a non-
707        identity transfer-coding, the Content-Length MUST be ignored. */
708
709     if(!checkheaders(data, "Transfer-Encoding:")) {
710       te = "Transfer-Encoding: chunked\r\n";
711     }
712     else {
713       /* The "Transfer-Encoding:" header was already added. */
714       te = "";
715     }
716   }
717
718   ptr = checkheaders(data, "Host:");
719   if(ptr) {
720     /* If we have a given custom Host: header, we extract the host name
721        in order to possibly use it for cookie reasons later on. */
722     char *start = ptr+strlen("Host:");
723     char *ptr;
724     while(*start && isspace((int)*start ))
725       start++;
726     ptr = start; /* start host-scanning here */
727
728     /* scan through the string to find the end (space or colon) */
729     while(*ptr && !isspace((int)*ptr) && !(':'==*ptr))
730       ptr++;
731     
732     if(ptr != start) {
733       int len=ptr-start;
734       conn->allocptr.cookiehost = malloc(len+1);
735       if(!conn->allocptr.cookiehost)
736         return CURLE_OUT_OF_MEMORY;
737       memcpy(conn->allocptr.cookiehost, start, len);
738       conn->allocptr.cookiehost[len]=0;
739     }
740   }    
741   else {
742     /* if ptr_host is already set, it is almost OK since we only re-use
743        connections to the very same host and port, but when we use a HTTP
744        proxy we have a persistant connect and yet we must change the Host:
745        header! */
746
747     if(conn->allocptr.host)
748       free(conn->allocptr.host);
749
750     /* When building Host: headers, we must put the host name within
751        [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
752        
753     if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
754        (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
755       /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
756          the port number in the host string */
757       conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
758                                     conn->bits.ipv6_ip?"[":"",
759                                     host,
760                                     conn->bits.ipv6_ip?"]":"");
761     else
762       conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
763                                     conn->bits.ipv6_ip?"[":"",
764                                     host,
765                                     conn->bits.ipv6_ip?"]":"",
766                                     conn->remote_port);
767   }
768
769   if(data->cookies) {
770     co = Curl_cookie_getlist(data->cookies,
771                              conn->allocptr.cookiehost?
772                              conn->allocptr.cookiehost:host, ppath,
773                              (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
774   }
775
776   if (data->change.proxy && *data->change.proxy &&
777       !data->set.tunnel_thru_httpproxy &&
778       !(conn->protocol&PROT_HTTPS))  {
779     /* The path sent to the proxy is in fact the entire URL */
780     ppath = data->change.url;
781   }
782   if(HTTPREQ_POST_FORM == data->set.httpreq) {
783     /* we must build the whole darned post sequence first, so that we have
784        a size of the whole shebang before we start to send it */
785      result = Curl_getFormData(&http->sendit, data->set.httppost,
786                                &http->postsize);
787      if(CURLE_OK != result) {
788        /* Curl_getFormData() doesn't use failf() */
789        failf(data, "failed creating formpost data");
790        return result;
791      }
792   }
793
794
795   if(!checkheaders(data, "Pragma:"))
796     http->p_pragma = "Pragma: no-cache\r\n";
797
798   if(!checkheaders(data, "Accept:"))
799     http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n";
800
801   if(( (HTTPREQ_POST == data->set.httpreq) ||
802        (HTTPREQ_POST_FORM == data->set.httpreq) ||
803        (HTTPREQ_PUT == data->set.httpreq) ) &&
804      conn->resume_from) {
805     /**********************************************************************
806      * Resuming upload in HTTP means that we PUT or POST and that we have
807      * got a resume_from value set. The resume value has already created
808      * a Range: header that will be passed along. We need to "fast forward"
809      * the file the given number of bytes and decrease the assume upload
810      * file size before we continue this venture in the dark lands of HTTP.
811      *********************************************************************/
812    
813     if(conn->resume_from < 0 ) {
814       /*
815        * This is meant to get the size of the present remote-file by itself.
816        * We don't support this now. Bail out!
817        */
818        conn->resume_from = 0;
819     }
820
821     if(conn->resume_from) {
822       /* do we still game? */
823       int passed=0;
824
825       /* Now, let's read off the proper amount of bytes from the
826          input. If we knew it was a proper file we could've just
827          fseek()ed but we only have a stream here */
828       do {
829         int readthisamountnow = (conn->resume_from - passed);
830         int actuallyread;
831
832         if(readthisamountnow > BUFSIZE)
833           readthisamountnow = BUFSIZE;
834
835         actuallyread =
836           data->set.fread(data->state.buffer, 1, readthisamountnow,
837                           data->set.in);
838
839         passed += actuallyread;
840         if(actuallyread != readthisamountnow) {
841           failf(data, "Could only read %d bytes from the input",
842                 passed);
843           return CURLE_READ_ERROR;
844         }
845       } while(passed != conn->resume_from); /* loop until done */
846
847       /* now, decrease the size of the read */
848       if(data->set.infilesize>0) {
849         data->set.infilesize -= conn->resume_from;
850
851         if(data->set.infilesize <= 0) {
852           failf(data, "File already completely uploaded");
853           return CURLE_PARTIAL_FILE;
854         }
855       }
856       /* we've passed, proceed as normal */
857     }
858   }
859   if(conn->bits.use_range) {
860     /*
861      * A range is selected. We use different headers whether we're downloading
862      * or uploading and we always let customized headers override our internal
863      * ones if any such are specified.
864      */
865     if((data->set.httpreq == HTTPREQ_GET) &&
866        !checkheaders(data, "Range:")) {
867       /* if a line like this was already allocated, free the previous one */
868       if(conn->allocptr.rangeline)
869         free(conn->allocptr.rangeline);
870       conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
871     }
872     else if((data->set.httpreq != HTTPREQ_GET) &&
873             !checkheaders(data, "Content-Range:")) {
874
875       if(conn->resume_from) {
876         /* This is because "resume" was selected */
877         long total_expected_size= conn->resume_from + data->set.infilesize;
878         conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%ld/%ld\r\n",
879                                       conn->range, total_expected_size-1,
880                                       total_expected_size);
881       }
882       else {
883         /* Range was selected and then we just pass the incoming range and 
884            append total size */
885         conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%d\r\n",
886                                       conn->range, data->set.infilesize);
887       }
888     }
889   }
890
891   do {
892     /* Use 1.1 unless the use specificly asked for 1.0 */
893     const char *httpstring=
894       data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
895
896     send_buffer *req_buffer;
897     struct curl_slist *headers=data->set.headers;
898
899     /* initialize a dynamic send-buffer */
900     req_buffer = add_buffer_init();
901
902     /* add the main request stuff */
903     add_bufferf(req_buffer,
904                 "%s " /* GET/HEAD/POST/PUT */
905                 "%s HTTP/%s\r\n" /* path */
906                 "%s" /* proxyuserpwd */
907                 "%s" /* userpwd */
908                 "%s" /* range */
909                 "%s" /* user agent */
910                 "%s" /* cookie */
911                 "%s" /* host */
912                 "%s" /* pragma */
913                 "%s" /* accept */
914                 "%s" /* accept-encoding */
915                 "%s" /* referer */
916                 "%s",/* transfer-encoding */
917
918                 data->set.customrequest?data->set.customrequest:
919                 (data->set.no_body?"HEAD":
920                  ((HTTPREQ_POST == data->set.httpreq) ||
921                   (HTTPREQ_POST_FORM == data->set.httpreq))?"POST":
922                  (HTTPREQ_PUT == data->set.httpreq)?"PUT":"GET"),
923                 ppath, httpstring,
924                 (conn->bits.proxy_user_passwd &&
925                  conn->allocptr.proxyuserpwd)?conn->allocptr.proxyuserpwd:"",
926                 (conn->bits.user_passwd && conn->allocptr.userpwd)?
927                 conn->allocptr.userpwd:"",
928                 (conn->bits.use_range && conn->allocptr.rangeline)?
929                 conn->allocptr.rangeline:"",
930                 (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
931                 conn->allocptr.uagent:"",
932                 (conn->allocptr.cookie?conn->allocptr.cookie:""), /* Cookie: <data> */
933                 (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
934                 http->p_pragma?http->p_pragma:"",
935                 http->p_accept?http->p_accept:"",
936                 (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
937                 conn->allocptr.accept_encoding:"", /* 08/28/02 jhrg */
938                 (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */,
939                 te
940                 );
941
942     if(co) {
943       int count=0;
944       struct Cookie *store=co;
945       /* now loop through all cookies that matched */
946       while(co) {
947         if(co->value && strlen(co->value)) {
948           if(0 == count) {
949             add_bufferf(req_buffer, "Cookie: ");
950           }
951           add_bufferf(req_buffer,
952                       "%s%s=%s", count?"; ":"", co->name, co->value);
953           count++;
954         }
955         co = co->next; /* next cookie please */
956       }
957       if(count) {
958         add_buffer(req_buffer, "\r\n", 2);
959       }
960       Curl_cookie_freelist(store); /* free the cookie list */
961       co=NULL;
962     }
963
964     if(data->set.timecondition) {
965       struct tm *thistime;
966
967       /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
968        * header family should have their times set in GMT as RFC2616 defines:
969        * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
970        * (GMT), without exception. For the purposes of HTTP, GMT is exactly
971        * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
972        */
973
974 #ifdef HAVE_GMTIME_R
975       /* thread-safe version */
976       struct tm keeptime;
977       thistime = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
978 #else
979       thistime = gmtime(&data->set.timevalue);
980 #endif
981       if(NULL == thistime) {
982         failf(data, "localtime() failed!");
983         return CURLE_OUT_OF_MEMORY;
984       }
985
986 #ifdef HAVE_STRFTIME
987       /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
988       strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S GMT", thistime);
989 #else
990       /* TODO: Right, we *could* write a replacement here */
991       strcpy(buf, "no strftime() support");
992 #endif
993       switch(data->set.timecondition) {
994       case CURL_TIMECOND_IFMODSINCE:
995       default:
996         add_bufferf(req_buffer,
997                     "If-Modified-Since: %s\r\n", buf);
998         break;
999       case CURL_TIMECOND_IFUNMODSINCE:
1000         add_bufferf(req_buffer,
1001                     "If-Unmodified-Since: %s\r\n", buf);
1002         break;
1003       case CURL_TIMECOND_LASTMOD:
1004         add_bufferf(req_buffer,
1005                     "Last-Modified: %s\r\n", buf);
1006         break;
1007       }
1008     }
1009
1010     while(headers) {
1011       char *ptr = strchr(headers->data, ':');
1012       if(ptr) {
1013         /* we require a colon for this to be a true header */
1014
1015         ptr++; /* pass the colon */
1016         while(*ptr && isspace((int)*ptr))
1017           ptr++;
1018
1019         if(*ptr) {
1020           /* only send this if the contents was non-blank */
1021
1022           add_bufferf(req_buffer, "%s\r\n", headers->data);
1023         }
1024       }
1025       headers = headers->next;
1026     }
1027
1028     http->postdata = NULL;  /* nothing to post at this point */
1029     Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
1030
1031     switch(data->set.httpreq) {
1032
1033     case HTTPREQ_POST_FORM:
1034       if(Curl_FormInit(&http->form, http->sendit)) {
1035         failf(data, "Internal HTTP POST error!");
1036         return CURLE_HTTP_POST_ERROR;
1037       }
1038
1039       /* set the read function to read from the generated form data */
1040       conn->fread = (curl_read_callback)Curl_FormReader;
1041       conn->fread_in = &http->form;
1042
1043       http->sending = HTTPSEND_BODY;
1044
1045       if(!conn->bits.upload_chunky)
1046         /* only add Content-Length if not uploading chunked */
1047         add_bufferf(req_buffer,
1048                     "Content-Length: %d\r\n", http->postsize);
1049
1050       if(!checkheaders(data, "Expect:")) {
1051         /* if not disabled explicitly we add a Expect: 100-continue
1052            to the headers which actually speeds up post operations (as
1053            there is one packet coming back from the web server) */
1054         add_bufferf(req_buffer,
1055                     "Expect: 100-continue\r\n");
1056         data->set.expect100header = TRUE;
1057       }
1058
1059       if(!checkheaders(data, "Content-Type:")) {
1060         /* Get Content-Type: line from Curl_FormReadOneLine, which happens
1061            to always be the first line. We can know this for sure since
1062            we always build the formpost linked list the same way!
1063
1064            The Content-Type header line also contains the MIME boundary
1065            string etc why disabling this header is likely to not make things
1066            work, but we support it anyway.
1067         */
1068         char contentType[256];
1069         int linelength=0;
1070         linelength = Curl_FormReadOneLine (contentType,
1071                                            sizeof(contentType),
1072                                            1,
1073                                            (FILE *)&http->form);
1074         if(linelength == -1) {
1075           failf(data, "Could not get Content-Type header line!");
1076           return CURLE_HTTP_POST_ERROR;
1077         }
1078         add_buffer(req_buffer, contentType, linelength);
1079       }
1080
1081       /* make the request end in a true CRLF */
1082       add_buffer(req_buffer, "\r\n", 2);
1083
1084       /* set upload size to the progress meter */
1085       Curl_pgrsSetUploadSize(data, http->postsize);
1086
1087       /* fire away the whole request to the server */
1088       result = add_buffer_send(req_buffer, conn->firstsocket, conn, 
1089                                &data->info.request_size);
1090       if(result)
1091         failf(data, "Failed sending POST request");
1092       else
1093         /* setup variables for the upcoming transfer */
1094         result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
1095                                &http->readbytecount,
1096                                conn->firstsocket,
1097                                &http->writebytecount);
1098       if(result) {
1099         Curl_formclean(http->sendit); /* free that whole lot */
1100         return result;
1101       }
1102       break;
1103
1104     case HTTPREQ_PUT: /* Let's PUT the data to the server! */
1105
1106       if((data->set.infilesize>0) && !conn->bits.upload_chunky)
1107         /* only add Content-Length if not uploading chunked */
1108         add_bufferf(req_buffer,
1109                     "Content-Length: %d\r\n", /* file size */
1110                     data->set.infilesize );
1111
1112       add_bufferf(req_buffer, "\r\n");
1113
1114       /* set the upload size to the progress meter */
1115       Curl_pgrsSetUploadSize(data, data->set.infilesize);
1116
1117       /* this sends the buffer and frees all the buffer resources */
1118       result = add_buffer_send(req_buffer, conn->firstsocket, conn,
1119                                &data->info.request_size);
1120       if(result)
1121         failf(data, "Failed sending POST request");
1122       else
1123         /* prepare for transfer */
1124         result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
1125                                &http->readbytecount,
1126                                conn->firstsocket,
1127                                &http->writebytecount);
1128       if(result)
1129         return result;
1130       break;
1131
1132     case HTTPREQ_POST:
1133       /* this is the simple POST, using x-www-form-urlencoded style */
1134
1135       if(!conn->bits.upload_chunky) {
1136         /* We only set Content-Length and allow a custom Content-Length if
1137            we don't upload data chunked, as RFC2616 forbids us to set both
1138            kinds of headers (Transfer-Encoding: chunked and Content-Length) */
1139
1140         if(!checkheaders(data, "Content-Length:"))
1141           /* we allow replacing this header, although it isn't very wise to
1142              actually set your own */
1143           add_bufferf(req_buffer,
1144                       "Content-Length: %d\r\n",
1145                       data->set.postfieldsize?
1146                       data->set.postfieldsize:
1147                       (data->set.postfields?strlen(data->set.postfields):0) );
1148       }
1149
1150       if(!checkheaders(data, "Content-Type:"))
1151         add_bufferf(req_buffer,
1152                     "Content-Type: application/x-www-form-urlencoded\r\n");
1153
1154       add_buffer(req_buffer, "\r\n", 2);
1155
1156       /* and here we setup the pointers to the actual data */
1157       if(data->set.postfields) {
1158         if(data->set.postfieldsize)
1159           http->postsize = data->set.postfieldsize;
1160         else
1161           http->postsize = strlen(data->set.postfields);
1162         http->postdata = data->set.postfields;
1163
1164         http->sending = HTTPSEND_BODY;
1165
1166         conn->fread = (curl_read_callback)readmoredata;
1167         conn->fread_in = (void *)conn;
1168
1169         /* set the upload size to the progress meter */
1170         Curl_pgrsSetUploadSize(data, http->postsize);
1171       }
1172       else
1173         /* set the upload size to the progress meter */
1174         Curl_pgrsSetUploadSize(data, data->set.infilesize);
1175
1176       /* issue the request, headers-only */
1177       result = add_buffer_send(req_buffer, conn->firstsocket, conn,
1178                                &data->info.request_size);
1179
1180       if(result)
1181         failf(data, "Failed sending HTTP POST request");
1182       else
1183         result =
1184           Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
1185                         &http->readbytecount,
1186                         conn->firstsocket,
1187                         &http->writebytecount);
1188       break;
1189
1190     default:
1191       add_buffer(req_buffer, "\r\n", 2);
1192       
1193       /* issue the request */
1194       result = add_buffer_send(req_buffer, conn->firstsocket, conn,
1195                                &data->info.request_size);
1196
1197       if(result)
1198         failf(data, "Failed sending HTTP request");
1199       else
1200         /* HTTP GET/HEAD download: */
1201         result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
1202                                &http->readbytecount,
1203                                http->postdata?conn->firstsocket:-1,
1204                                http->postdata?&http->writebytecount:NULL);
1205     }
1206     if(result)
1207       return result;
1208   } while (0); /* this is just a left-over from the multiple document download
1209                   attempts */
1210
1211   return CURLE_OK;
1212 }
1213 #endif