Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Utilities / cmcurl / http.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2007, 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 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36 #ifdef HAVE_SYS_STAT_H
37 #include <sys/stat.h>
38 #endif
39
40 #ifdef WIN32
41 #include <time.h>
42 #include <io.h>
43 #else
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 #ifdef HAVE_NETINET_IN_H
48 #include <netinet/in.h>
49 #endif
50 #ifdef HAVE_SYS_TIME_H
51 #include <sys/time.h>
52 #endif
53
54 #ifdef HAVE_TIME_H
55 #ifdef TIME_WITH_SYS_TIME
56 #include <time.h>
57 #endif
58 #endif
59
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 #include <netdb.h>
64 #ifdef HAVE_ARPA_INET_H
65 #include <arpa/inet.h>
66 #endif
67 #ifdef HAVE_NET_IF_H
68 #include <net/if.h>
69 #endif
70 #include <sys/ioctl.h>
71 #include <signal.h>
72
73 #ifdef HAVE_SYS_PARAM_H
74 #include <sys/param.h>
75 #endif
76
77 #endif
78
79 #include "urldata.h"
80 #include <curl/curl.h>
81 #include "transfer.h"
82 #include "sendf.h"
83 #include "easyif.h" /* for Curl_convert_... prototypes */
84 #include "formdata.h"
85 #include "progress.h"
86 #include "base64.h"
87 #include "cookie.h"
88 #include "strequal.h"
89 #include "sslgen.h"
90 #include "http_digest.h"
91 #include "http_ntlm.h"
92 #include "http_negotiate.h"
93 #include "url.h"
94 #include "share.h"
95 #include "hostip.h"
96 #include "http.h"
97 #include "memory.h"
98 #include "select.h"
99 #include "parsedate.h" /* for the week day and month names */
100 #include "strtoofft.h"
101 #include "multiif.h"
102
103 #define _MPRINTF_REPLACE /* use our functions only */
104 #include <curl/mprintf.h>
105
106 /* The last #include file should be: */
107 #include "memdebug.h"
108
109 /*
110  * checkheaders() checks the linked list of custom HTTP headers for a
111  * particular header (prefix).
112  *
113  * Returns a pointer to the first matching header or NULL if none matched.
114  */
115 static char *checkheaders(struct SessionHandle *data, const char *thisheader)
116 {
117   struct curl_slist *head;
118   size_t thislen = strlen(thisheader);
119
120   for(head = data->set.headers; head; head=head->next) {
121     if(strnequal(head->data, thisheader, thislen))
122       return head->data;
123   }
124   return NULL;
125 }
126
127 /*
128  * Curl_output_basic() sets up an Authorization: header (or the proxy version)
129  * for HTTP Basic authentication.
130  *
131  * Returns CURLcode.
132  */
133 static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy)
134 {
135   char *authorization;
136   struct SessionHandle *data=conn->data;
137   char **userp;
138   char *user;
139   char *pwd;
140
141   if(proxy) {
142     userp = &conn->allocptr.proxyuserpwd;
143     user = conn->proxyuser;
144     pwd = conn->proxypasswd;
145   }
146   else {
147     userp = &conn->allocptr.userpwd;
148     user = conn->user;
149     pwd = conn->passwd;
150   }
151
152   snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
153   if(Curl_base64_encode(data, data->state.buffer,
154                         strlen(data->state.buffer),
155                         &authorization) > 0) {
156     if(*userp)
157       free(*userp);
158     *userp = aprintf( "%sAuthorization: Basic %s\r\n",
159                       proxy?"Proxy-":"",
160                       authorization);
161     free(authorization);
162   }
163   else
164     return CURLE_OUT_OF_MEMORY;
165   return CURLE_OK;
166 }
167
168 /* pickoneauth() selects the most favourable authentication method from the
169  * ones available and the ones we want.
170  *
171  * return TRUE if one was picked
172  */
173 static bool pickoneauth(struct auth *pick)
174 {
175   bool picked;
176   /* only deal with authentication we want */
177   long avail = pick->avail & pick->want;
178   picked = TRUE;
179
180   /* The order of these checks is highly relevant, as this will be the order
181      of preference in case of the existence of multiple accepted types. */
182   if(avail & CURLAUTH_GSSNEGOTIATE)
183     pick->picked = CURLAUTH_GSSNEGOTIATE;
184   else if(avail & CURLAUTH_DIGEST)
185     pick->picked = CURLAUTH_DIGEST;
186   else if(avail & CURLAUTH_NTLM)
187     pick->picked = CURLAUTH_NTLM;
188   else if(avail & CURLAUTH_BASIC)
189     pick->picked = CURLAUTH_BASIC;
190   else {
191     pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
192     picked = FALSE;
193   }
194   pick->avail = CURLAUTH_NONE; /* clear it here */
195
196   return picked;
197 }
198
199 /*
200  * perhapsrewind()
201  *
202  * If we are doing POST or PUT {
203  *   If we have more data to send {
204  *     If we are doing NTLM {
205  *       Keep sending since we must not disconnect
206  *     }
207  *     else {
208  *       If there is more than just a little data left to send, close
209  *       the current connection by force.
210  *     }
211  *   }
212  *   If we have sent any data {
213  *     If we don't have track of all the data {
214  *       call app to tell it to rewind
215  *     }
216  *     else {
217  *       rewind internally so that the operation can restart fine
218  *     }
219  *   }
220  * }
221  */
222 static CURLcode perhapsrewind(struct connectdata *conn)
223 {
224   struct SessionHandle *data = conn->data;
225   struct HTTP *http = data->reqdata.proto.http;
226   struct Curl_transfer_keeper *k = &data->reqdata.keep;
227   curl_off_t bytessent;
228   curl_off_t expectsend = -1; /* default is unknown */
229
230   if(!http)
231     /* If this is still NULL, we have not reach very far and we can
232        safely skip this rewinding stuff */
233     return CURLE_OK;
234
235   bytessent = http->writebytecount;
236
237   if(conn->bits.authneg)
238     /* This is a state where we are known to be negotiating and we don't send
239        any data then. */
240     expectsend = 0;
241   else {
242     /* figure out how much data we are expected to send */
243     switch(data->set.httpreq) {
244     case HTTPREQ_POST:
245       if(data->set.postfieldsize != -1)
246         expectsend = data->set.postfieldsize;
247       break;
248     case HTTPREQ_PUT:
249       if(data->set.infilesize != -1)
250         expectsend = data->set.infilesize;
251       break;
252     case HTTPREQ_POST_FORM:
253       expectsend = http->postsize;
254       break;
255     default:
256       break;
257     }
258   }
259
260   conn->bits.rewindaftersend = FALSE; /* default */
261
262   if((expectsend == -1) || (expectsend > bytessent)) {
263     /* There is still data left to send */
264     if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
265        (data->state.authhost.picked == CURLAUTH_NTLM)) {
266       if(((expectsend - bytessent) < 2000) ||
267          (conn->ntlm.state != NTLMSTATE_NONE)) {
268         /* The NTLM-negotiation has started *OR* there is just a little (<2K)
269            data left to send, keep on sending. */
270
271         /* rewind data when completely done sending! */
272         if(!conn->bits.authneg)
273           conn->bits.rewindaftersend = TRUE;
274
275         return CURLE_OK;
276       }
277       if(conn->bits.close)
278         /* this is already marked to get closed */
279         return CURLE_OK;
280
281       infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
282             " bytes\n", (curl_off_t)(expectsend - bytessent));
283     }
284
285     /* This is not NTLM or NTLM with many bytes left to send: close
286      */
287     conn->bits.close = TRUE;
288     k->size = 0; /* don't download any more than 0 bytes */
289   }
290
291   if(bytessent)
292     return Curl_readrewind(conn);
293
294   return CURLE_OK;
295 }
296
297 /*
298  * Curl_http_auth_act() gets called when a all HTTP headers have been received
299  * and it checks what authentication methods that are available and decides
300  * which one (if any) to use. It will set 'newurl' if an auth metod was
301  * picked.
302  */
303
304 CURLcode Curl_http_auth_act(struct connectdata *conn)
305 {
306   struct SessionHandle *data = conn->data;
307   bool pickhost = FALSE;
308   bool pickproxy = FALSE;
309   CURLcode code = CURLE_OK;
310
311   if(100 == data->reqdata.keep.httpcode)
312     /* this is a transient response code, ignore */
313     return CURLE_OK;
314
315   if(data->state.authproblem)
316     return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
317
318   if(conn->bits.user_passwd &&
319      ((data->reqdata.keep.httpcode == 401) ||
320       (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) {
321     pickhost = pickoneauth(&data->state.authhost);
322     if(!pickhost)
323       data->state.authproblem = TRUE;
324   }
325   if(conn->bits.proxy_user_passwd &&
326      ((data->reqdata.keep.httpcode == 407) ||
327       (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) {
328     pickproxy = pickoneauth(&data->state.authproxy);
329     if(!pickproxy)
330       data->state.authproblem = TRUE;
331   }
332
333   if(pickhost || pickproxy) {
334     data->reqdata.newurl = strdup(data->change.url); /* clone URL */
335
336     if((data->set.httpreq != HTTPREQ_GET) &&
337        (data->set.httpreq != HTTPREQ_HEAD) &&
338        !conn->bits.rewindaftersend) {
339       code = perhapsrewind(conn);
340       if(code)
341         return code;
342     }
343   }
344
345   else if((data->reqdata.keep.httpcode < 300) &&
346           (!data->state.authhost.done) &&
347           conn->bits.authneg) {
348     /* no (known) authentication available,
349        authentication is not "done" yet and
350        no authentication seems to be required and
351        we didn't try HEAD or GET */
352     if((data->set.httpreq != HTTPREQ_GET) &&
353        (data->set.httpreq != HTTPREQ_HEAD)) {
354       data->reqdata.newurl = strdup(data->change.url); /* clone URL */
355       data->state.authhost.done = TRUE;
356     }
357   }
358   if (Curl_http_should_fail(conn)) {
359     failf (data, "The requested URL returned error: %d",
360            data->reqdata.keep.httpcode);
361     code = CURLE_HTTP_RETURNED_ERROR;
362   }
363
364   return code;
365 }
366
367 /**
368  * Curl_http_output_auth() setups the authentication headers for the
369  * host/proxy and the correct authentication
370  * method. conn->data->state.authdone is set to TRUE when authentication is
371  * done.
372  *
373  * @param conn all information about the current connection
374  * @param request pointer to the request keyword
375  * @param path pointer to the requested path
376  * @param proxytunnel boolean if this is the request setting up a "proxy
377  * tunnel"
378  *
379  * @returns CURLcode
380  */
381 static CURLcode
382 Curl_http_output_auth(struct connectdata *conn,
383                       char *request,
384                       char *path,
385                       bool proxytunnel) /* TRUE if this is the request setting
386                                            up the proxy tunnel */
387 {
388   CURLcode result = CURLE_OK;
389   struct SessionHandle *data = conn->data;
390   char *auth=NULL;
391   struct auth *authhost;
392   struct auth *authproxy;
393
394   curlassert(data);
395
396   authhost = &data->state.authhost;
397   authproxy = &data->state.authproxy;
398
399   if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
400      conn->bits.user_passwd)
401     /* continue please */ ;
402   else {
403     authhost->done = TRUE;
404     authproxy->done = TRUE;
405     return CURLE_OK; /* no authentication with no user or password */
406   }
407
408   if(authhost->want && !authhost->picked)
409     /* The app has selected one or more methods, but none has been picked
410        so far by a server round-trip. Then we set the picked one to the
411        want one, and if this is one single bit it'll be used instantly. */
412     authhost->picked = authhost->want;
413
414   if(authproxy->want && !authproxy->picked)
415     /* The app has selected one or more methods, but none has been picked so
416        far by a proxy round-trip. Then we set the picked one to the want one,
417        and if this is one single bit it'll be used instantly. */
418     authproxy->picked = authproxy->want;
419
420   /* Send proxy authentication header if needed */
421   if (conn->bits.httpproxy &&
422       (conn->bits.tunnel_proxy == proxytunnel)) {
423 #ifdef USE_NTLM
424     if(authproxy->picked == CURLAUTH_NTLM) {
425       auth=(char *)"NTLM";
426       result = Curl_output_ntlm(conn, TRUE);
427       if(result)
428         return result;
429     }
430     else
431 #endif
432       if(authproxy->picked == CURLAUTH_BASIC) {
433         /* Basic */
434         if(conn->bits.proxy_user_passwd &&
435            !checkheaders(data, "Proxy-authorization:")) {
436           auth=(char *)"Basic";
437           result = Curl_output_basic(conn, TRUE);
438           if(result)
439             return result;
440         }
441         /* NOTE: Curl_output_basic() should set 'done' TRUE, as the other auth
442            functions work that way */
443         authproxy->done = TRUE;
444       }
445 #ifndef CURL_DISABLE_CRYPTO_AUTH
446       else if(authproxy->picked == CURLAUTH_DIGEST) {
447         auth=(char *)"Digest";
448         result = Curl_output_digest(conn,
449                                     TRUE, /* proxy */
450                                     (unsigned char *)request,
451                                     (unsigned char *)path);
452         if(result)
453           return result;
454       }
455 #endif
456       if(auth) {
457         infof(data, "Proxy auth using %s with user '%s'\n",
458               auth, conn->proxyuser?conn->proxyuser:"");
459         authproxy->multi = (bool)(!authproxy->done);
460       }
461       else
462         authproxy->multi = FALSE;
463     }
464   else
465     /* we have no proxy so let's pretend we're done authenticating
466        with it */
467     authproxy->done = TRUE;
468
469   /* To prevent the user+password to get sent to other than the original
470      host due to a location-follow, we do some weirdo checks here */
471   if(!data->state.this_is_a_follow ||
472      conn->bits.netrc ||
473      !data->state.first_host ||
474      curl_strequal(data->state.first_host, conn->host.name) ||
475      data->set.http_disable_hostname_check_before_authentication) {
476
477     /* Send web authentication header if needed */
478     {
479       auth = NULL;
480 #ifdef HAVE_GSSAPI
481       if((authhost->picked == CURLAUTH_GSSNEGOTIATE) &&
482          data->state.negotiate.context &&
483          !GSS_ERROR(data->state.negotiate.status)) {
484         auth=(char *)"GSS-Negotiate";
485         result = Curl_output_negotiate(conn);
486         if (result)
487           return result;
488         authhost->done = TRUE;
489       }
490       else
491 #endif
492 #ifdef USE_NTLM
493       if(authhost->picked == CURLAUTH_NTLM) {
494         auth=(char *)"NTLM";
495         result = Curl_output_ntlm(conn, FALSE);
496         if(result)
497           return result;
498       }
499       else
500 #endif
501       {
502 #ifndef CURL_DISABLE_CRYPTO_AUTH
503         if(authhost->picked == CURLAUTH_DIGEST) {
504           auth=(char *)"Digest";
505           result = Curl_output_digest(conn,
506                                       FALSE, /* not a proxy */
507                                       (unsigned char *)request,
508                                       (unsigned char *)path);
509           if(result)
510             return result;
511         } else
512 #endif
513         if(authhost->picked == CURLAUTH_BASIC) {
514           if(conn->bits.user_passwd &&
515              !checkheaders(data, "Authorization:")) {
516             auth=(char *)"Basic";
517             result = Curl_output_basic(conn, FALSE);
518             if(result)
519               return result;
520           }
521           /* basic is always ready */
522           authhost->done = TRUE;
523         }
524       }
525       if(auth) {
526         infof(data, "Server auth using %s with user '%s'\n",
527               auth, conn->user);
528
529         authhost->multi = (bool)(!authhost->done);
530       }
531       else
532         authhost->multi = FALSE;
533     }
534   }
535   else
536     authhost->done = TRUE;
537
538   return result;
539 }
540
541
542 /*
543  * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
544  * headers. They are dealt with both in the transfer.c main loop and in the
545  * proxy CONNECT loop.
546  */
547
548 CURLcode Curl_http_input_auth(struct connectdata *conn,
549                               int httpcode,
550                               char *header) /* the first non-space */
551 {
552   /*
553    * This resource requires authentication
554    */
555   struct SessionHandle *data = conn->data;
556
557   long *availp;
558   char *start;
559   struct auth *authp;
560
561   if (httpcode == 407) {
562     start = header+strlen("Proxy-authenticate:");
563     availp = &data->info.proxyauthavail;
564     authp = &data->state.authproxy;
565   }
566   else {
567     start = header+strlen("WWW-Authenticate:");
568     availp = &data->info.httpauthavail;
569     authp = &data->state.authhost;
570   }
571
572   /* pass all white spaces */
573   while(*start && ISSPACE(*start))
574     start++;
575
576   /*
577    * Here we check if we want the specific single authentication (using ==) and
578    * if we do, we initiate usage of it.
579    *
580    * If the provided authentication is wanted as one out of several accepted
581    * types (using &), we OR this authentication type to the authavail
582    * variable.
583    */
584
585 #ifdef HAVE_GSSAPI
586   if (checkprefix("GSS-Negotiate", start) ||
587       checkprefix("Negotiate", start)) {
588     *availp |= CURLAUTH_GSSNEGOTIATE;
589     authp->avail |= CURLAUTH_GSSNEGOTIATE;
590     if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
591       /* if exactly this is wanted, go */
592       int neg = Curl_input_negotiate(conn, start);
593       if (neg == 0) {
594         data->reqdata.newurl = strdup(data->change.url);
595         data->state.authproblem = (data->reqdata.newurl == NULL);
596       }
597       else {
598         infof(data, "Authentication problem. Ignoring this.\n");
599         data->state.authproblem = TRUE;
600       }
601     }
602   }
603   else
604 #endif
605 #ifdef USE_NTLM
606     /* NTLM support requires the SSL crypto libs */
607     if(checkprefix("NTLM", start)) {
608       *availp |= CURLAUTH_NTLM;
609       authp->avail |= CURLAUTH_NTLM;
610       if(authp->picked == CURLAUTH_NTLM) {
611         /* NTLM authentication is picked and activated */
612         CURLntlm ntlm =
613           Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
614
615         if(CURLNTLM_BAD != ntlm)
616           data->state.authproblem = FALSE;
617         else {
618           infof(data, "Authentication problem. Ignoring this.\n");
619           data->state.authproblem = TRUE;
620         }
621       }
622     }
623     else
624 #endif
625 #ifndef CURL_DISABLE_CRYPTO_AUTH
626       if(checkprefix("Digest", start)) {
627         if((authp->avail & CURLAUTH_DIGEST) != 0) {
628           infof(data, "Ignoring duplicate digest auth header.\n");
629         }
630         else {
631           CURLdigest dig;
632           *availp |= CURLAUTH_DIGEST;
633           authp->avail |= CURLAUTH_DIGEST;
634
635           /* We call this function on input Digest headers even if Digest
636            * authentication isn't activated yet, as we need to store the
637            * incoming data from this header in case we are gonna use Digest. */
638           dig = Curl_input_digest(conn, (bool)(httpcode == 407), start);
639
640           if(CURLDIGEST_FINE != dig) {
641             infof(data, "Authentication problem. Ignoring this.\n");
642             data->state.authproblem = TRUE;
643           }
644         }
645       }
646       else
647 #endif
648       if(checkprefix("Basic", start)) {
649         *availp |= CURLAUTH_BASIC;
650         authp->avail |= CURLAUTH_BASIC;
651         if(authp->picked == CURLAUTH_BASIC) {
652           /* We asked for Basic authentication but got a 40X back
653              anyway, which basicly means our name+password isn't
654              valid. */
655           authp->avail = CURLAUTH_NONE;
656           infof(data, "Authentication problem. Ignoring this.\n");
657           data->state.authproblem = TRUE;
658         }
659       }
660
661   return CURLE_OK;
662 }
663
664 /**
665  * Curl_http_should_fail() determines whether an HTTP response has gotten us
666  * into an error state or not.
667  *
668  * @param conn all information about the current connection
669  *
670  * @retval 0 communications should continue
671  *
672  * @retval 1 communications should not continue
673  */
674 int Curl_http_should_fail(struct connectdata *conn)
675 {
676   struct SessionHandle *data;
677   struct Curl_transfer_keeper *k;
678
679   curlassert(conn);
680   data = conn->data;
681   curlassert(data);
682
683   /*
684   ** For readability
685   */
686   k = &data->reqdata.keep;
687
688   /*
689   ** If we haven't been asked to fail on error,
690   ** don't fail.
691   */
692   if (!data->set.http_fail_on_error)
693     return 0;
694
695   /*
696   ** Any code < 400 is never terminal.
697   */
698   if (k->httpcode < 400)
699     return 0;
700
701   if (data->reqdata.resume_from &&
702       (data->set.httpreq==HTTPREQ_GET) &&
703       (k->httpcode == 416)) {
704     /* "Requested Range Not Satisfiable", just proceed and
705        pretend this is no error */
706     return 0;
707   }
708
709   /*
710   ** Any code >= 400 that's not 401 or 407 is always
711   ** a terminal error
712   */
713   if ((k->httpcode != 401) &&
714       (k->httpcode != 407))
715     return 1;
716
717   /*
718   ** All we have left to deal with is 401 and 407
719   */
720   curlassert((k->httpcode == 401) || (k->httpcode == 407));
721
722   /*
723   ** Examine the current authentication state to see if this
724   ** is an error.  The idea is for this function to get
725   ** called after processing all the headers in a response
726   ** message.  So, if we've been to asked to authenticate a
727   ** particular stage, and we've done it, we're OK.  But, if
728   ** we're already completely authenticated, it's not OK to
729   ** get another 401 or 407.
730   **
731   ** It is possible for authentication to go stale such that
732   ** the client needs to reauthenticate.  Once that info is
733   ** available, use it here.
734   */
735 #if 0 /* set to 1 when debugging this functionality */
736   infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
737   infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant);
738   infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail);
739   infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
740   infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
741   infof(data,"%s: newurl = %s\n",__FUNCTION__,data->reqdata.newurl ? data->reqdata.newurl : "(null)");
742   infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem);
743 #endif
744
745   /*
746   ** Either we're not authenticating, or we're supposed to
747   ** be authenticating something else.  This is an error.
748   */
749   if((k->httpcode == 401) && !conn->bits.user_passwd)
750     return TRUE;
751   if((k->httpcode == 407) && !conn->bits.proxy_user_passwd)
752     return TRUE;
753
754   return data->state.authproblem;
755 }
756
757 /*
758  * readmoredata() is a "fread() emulation" to provide POST and/or request
759  * data. It is used when a huge POST is to be made and the entire chunk wasn't
760  * sent in the first send(). This function will then be called from the
761  * transfer.c loop when more data is to be sent to the peer.
762  *
763  * Returns the amount of bytes it filled the buffer with.
764  */
765 static size_t readmoredata(char *buffer,
766                            size_t size,
767                            size_t nitems,
768                            void *userp)
769 {
770   struct connectdata *conn = (struct connectdata *)userp;
771   struct HTTP *http = conn->data->reqdata.proto.http;
772   size_t fullsize = size * nitems;
773
774   if(0 == http->postsize)
775     /* nothing to return */
776     return 0;
777
778   /* make sure that a HTTP request is never sent away chunked! */
779   conn->bits.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST);
780
781   if(http->postsize <= (curl_off_t)fullsize) {
782     memcpy(buffer, http->postdata, (size_t)http->postsize);
783     fullsize = (size_t)http->postsize;
784
785     if(http->backup.postsize) {
786       /* move backup data into focus and continue on that */
787       http->postdata = http->backup.postdata;
788       http->postsize = http->backup.postsize;
789       conn->fread =    http->backup.fread;
790       conn->fread_in = http->backup.fread_in;
791
792       http->sending++; /* move one step up */
793
794       http->backup.postsize=0;
795     }
796     else
797       http->postsize = 0;
798
799     return fullsize;
800   }
801
802   memcpy(buffer, http->postdata, fullsize);
803   http->postdata += fullsize;
804   http->postsize -= fullsize;
805
806   return fullsize;
807 }
808
809 /* ------------------------------------------------------------------------- */
810 /*
811  * The add_buffer series of functions are used to build one large memory chunk
812  * from repeated function invokes. Used so that the entire HTTP request can
813  * be sent in one go.
814  */
815
816 struct send_buffer {
817   char *buffer;
818   size_t size_max;
819   size_t size_used;
820 };
821 typedef struct send_buffer send_buffer;
822
823 static CURLcode add_custom_headers(struct connectdata *conn,
824                                    send_buffer *req_buffer);
825 static CURLcode
826  add_buffer(send_buffer *in, const void *inptr, size_t size);
827
828 /*
829  * add_buffer_init() sets up and returns a fine buffer struct
830  */
831 static
832 send_buffer *add_buffer_init(void)
833 {
834   send_buffer *blonk;
835   blonk=(send_buffer *)malloc(sizeof(send_buffer));
836   if(blonk) {
837     memset(blonk, 0, sizeof(send_buffer));
838     return blonk;
839   }
840   return NULL; /* failed, go home */
841 }
842
843 /*
844  * add_buffer_send() sends a header buffer and frees all associated memory.
845  * Body data may be appended to the header data if desired.
846  *
847  * Returns CURLcode
848  */
849 static
850 CURLcode add_buffer_send(send_buffer *in,
851                          struct connectdata *conn,
852                          long *bytes_written, /* add the number of sent
853                                                  bytes to this counter */
854                          size_t included_body_bytes, /* how much of the buffer
855                                         contains body data (for log tracing) */
856                          int socketindex)
857
858 {
859   ssize_t amount;
860   CURLcode res;
861   char *ptr;
862   size_t size;
863   struct HTTP *http = conn->data->reqdata.proto.http;
864   size_t sendsize;
865   curl_socket_t sockfd;
866
867   curlassert(socketindex <= SECONDARYSOCKET);
868
869   sockfd = conn->sock[socketindex];
870
871   /* The looping below is required since we use non-blocking sockets, but due
872      to the circumstances we will just loop and try again and again etc */
873
874   ptr = in->buffer;
875   size = in->size_used;
876
877 #ifdef CURL_DOES_CONVERSIONS
878   if(size - included_body_bytes > 0) {
879     res = Curl_convert_to_network(conn->data, ptr, size - included_body_bytes);
880     /* Curl_convert_to_network calls failf if unsuccessful */
881     if(res != CURLE_OK) {
882       /* conversion failed, free memory and return to the caller */
883       if(in->buffer)
884         free(in->buffer);
885       free(in);
886       return res;
887     }
888   }
889 #endif /* CURL_DOES_CONVERSIONS */
890
891   if(conn->protocol & PROT_HTTPS) {
892     /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
893        when we speak HTTPS, as if only a fraction of it is sent now, this data
894        needs to fit into the normal read-callback buffer later on and that
895        buffer is using this size.
896     */
897
898     sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
899
900     /* OpenSSL is very picky and we must send the SAME buffer pointer to the
901        library when we attempt to re-send this buffer. Sending the same data
902        is not enough, we must use the exact same address. For this reason, we
903        must copy the data to the uploadbuffer first, since that is the buffer
904        we will be using if this send is retried later.
905     */
906     memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
907     ptr = conn->data->state.uploadbuffer;
908   }
909   else
910     sendsize = size;
911
912   res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
913
914   if(CURLE_OK == res) {
915
916     if(conn->data->set.verbose) {
917       /* this data _may_ contain binary stuff */
918       Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr,
919                  (size_t)(amount-included_body_bytes), conn);
920       if (included_body_bytes)
921         Curl_debug(conn->data, CURLINFO_DATA_OUT,
922                    ptr+amount-included_body_bytes,
923                    (size_t)included_body_bytes, conn);
924     }
925
926     *bytes_written += amount;
927
928     if(http) {
929       if((size_t)amount != size) {
930         /* The whole request could not be sent in one system call. We must
931            queue it up and send it later when we get the chance. We must not
932            loop here and wait until it might work again. */
933
934         size -= amount;
935
936         ptr = in->buffer + amount;
937
938         /* backup the currently set pointers */
939         http->backup.fread = conn->fread;
940         http->backup.fread_in = conn->fread_in;
941         http->backup.postdata = http->postdata;
942         http->backup.postsize = http->postsize;
943
944         /* set the new pointers for the request-sending */
945         conn->fread = (curl_read_callback)readmoredata;
946         conn->fread_in = (void *)conn;
947         http->postdata = ptr;
948         http->postsize = (curl_off_t)size;
949
950         http->send_buffer = in;
951         http->sending = HTTPSEND_REQUEST;
952
953         return CURLE_OK;
954       }
955       http->sending = HTTPSEND_BODY;
956       /* the full buffer was sent, clean up and return */
957     }
958     else {
959       if((size_t)amount != size)
960         /* We have no continue-send mechanism now, fail. This can only happen
961            when this function is used from the CONNECT sending function. We
962            currently (stupidly) assume that the whole request is always sent
963            away in the first single chunk.
964
965            This needs FIXing.
966         */
967         return CURLE_SEND_ERROR;
968       else
969         conn->writechannel_inuse = FALSE;
970     }
971   }
972   if(in->buffer)
973     free(in->buffer);
974   free(in);
975
976   return res;
977 }
978
979
980 /*
981  * add_bufferf() add the formatted input to the buffer.
982  */
983 static
984 CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
985 {
986   char *s;
987   va_list ap;
988   va_start(ap, fmt);
989   s = vaprintf(fmt, ap); /* this allocs a new string to append */
990   va_end(ap);
991
992   if(s) {
993     CURLcode result = add_buffer(in, s, strlen(s));
994     free(s);
995     if(CURLE_OK == result)
996       return CURLE_OK;
997   }
998   /* If we failed, we cleanup the whole buffer and return error */
999   if(in->buffer)
1000     free(in->buffer);
1001   free(in);
1002   return CURLE_OUT_OF_MEMORY;
1003 }
1004
1005 /*
1006  * add_buffer() appends a memory chunk to the existing buffer
1007  */
1008 static
1009 CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
1010 {
1011   char *new_rb;
1012   size_t new_size;
1013
1014   if(!in->buffer ||
1015      ((in->size_used + size) > (in->size_max - 1))) {
1016     new_size = (in->size_used+size)*2;
1017     if(in->buffer)
1018       /* we have a buffer, enlarge the existing one */
1019       new_rb = (char *)realloc(in->buffer, new_size);
1020     else
1021       /* create a new buffer */
1022       new_rb = (char *)malloc(new_size);
1023
1024     if(!new_rb)
1025       return CURLE_OUT_OF_MEMORY;
1026
1027     in->buffer = new_rb;
1028     in->size_max = new_size;
1029   }
1030   memcpy(&in->buffer[in->size_used], inptr, size);
1031
1032   in->size_used += size;
1033
1034   return CURLE_OK;
1035 }
1036
1037 /* end of the add_buffer functions */
1038 /* ------------------------------------------------------------------------- */
1039
1040 /*
1041  * Curl_compareheader()
1042  *
1043  * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
1044  * Pass headers WITH the colon.
1045  */
1046 bool
1047 Curl_compareheader(char *headerline,    /* line to check */
1048                    const char *header,  /* header keyword _with_ colon */
1049                    const char *content) /* content string to find */
1050 {
1051   /* RFC2616, section 4.2 says: "Each header field consists of a name followed
1052    * by a colon (":") and the field value. Field names are case-insensitive.
1053    * The field value MAY be preceded by any amount of LWS, though a single SP
1054    * is preferred." */
1055
1056   size_t hlen = strlen(header);
1057   size_t clen;
1058   size_t len;
1059   char *start;
1060   char *end;
1061
1062   if(!strnequal(headerline, header, hlen))
1063     return FALSE; /* doesn't start with header */
1064
1065   /* pass the header */
1066   start = &headerline[hlen];
1067
1068   /* pass all white spaces */
1069   while(*start && ISSPACE(*start))
1070     start++;
1071
1072   /* find the end of the header line */
1073   end = strchr(start, '\r'); /* lines end with CRLF */
1074   if(!end) {
1075     /* in case there's a non-standard compliant line here */
1076     end = strchr(start, '\n');
1077
1078     if(!end)
1079       /* hm, there's no line ending here, use the zero byte! */
1080       end = strchr(start, '\0');
1081   }
1082
1083   len = end-start; /* length of the content part of the input line */
1084   clen = strlen(content); /* length of the word to find */
1085
1086   /* find the content string in the rest of the line */
1087   for(;len>=clen;len--, start++) {
1088     if(strnequal(start, content, clen))
1089       return TRUE; /* match! */
1090   }
1091
1092   return FALSE; /* no match */
1093 }
1094
1095 /*
1096  * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
1097  * function will issue the necessary commands to get a seamless tunnel through
1098  * this proxy. After that, the socket can be used just as a normal socket.
1099  *
1100  * This badly needs to be rewritten. CONNECT should be sent and dealt with
1101  * like any ordinary HTTP request, and not specially crafted like this. This
1102  * function only remains here like this for now since the rewrite is a bit too
1103  * much work to do at the moment.
1104  *
1105  * This function is BLOCKING which is nasty for all multi interface using apps.
1106  */
1107
1108 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
1109                            int sockindex,
1110                            char *hostname,
1111                            int remote_port)
1112 {
1113   int subversion=0;
1114   struct SessionHandle *data=conn->data;
1115   struct Curl_transfer_keeper *k = &data->reqdata.keep;
1116   CURLcode result;
1117   int res;
1118   size_t nread;   /* total size read */
1119   int perline; /* count bytes per line */
1120   int keepon=TRUE;
1121   ssize_t gotbytes;
1122   char *ptr;
1123   long timeout =
1124     data->set.timeout?data->set.timeout:3600; /* in seconds */
1125   char *line_start;
1126   char *host_port;
1127   curl_socket_t tunnelsocket = conn->sock[sockindex];
1128   send_buffer *req_buffer;
1129   curl_off_t cl=0;
1130   bool closeConnection = FALSE;
1131
1132 #define SELECT_OK      0
1133 #define SELECT_ERROR   1
1134 #define SELECT_TIMEOUT 2
1135   int error = SELECT_OK;
1136
1137   infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
1138   conn->bits.proxy_connect_closed = FALSE;
1139
1140   do {
1141     if(data->reqdata.newurl) {
1142       /* This only happens if we've looped here due to authentication reasons,
1143          and we don't really use the newly cloned URL here then. Just free()
1144          it. */
1145       free(data->reqdata.newurl);
1146       data->reqdata.newurl = NULL;
1147     }
1148
1149     /* initialize a dynamic send-buffer */
1150     req_buffer = add_buffer_init();
1151
1152     if(!req_buffer)
1153       return CURLE_OUT_OF_MEMORY;
1154
1155     host_port = aprintf("%s:%d", hostname, remote_port);
1156     if(!host_port)
1157       return CURLE_OUT_OF_MEMORY;
1158
1159     /* Setup the proxy-authorization header, if any */
1160     result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
1161
1162     if(CURLE_OK == result) {
1163       char *host=(char *)"";
1164       const char *proxyconn="";
1165       const char *useragent="";
1166
1167       if(!checkheaders(data, "Host:")) {
1168         host = aprintf("Host: %s\r\n", host_port);
1169         if(!host)
1170           result = CURLE_OUT_OF_MEMORY;
1171       }
1172       if(!checkheaders(data, "Proxy-Connection:"))
1173         proxyconn = "Proxy-Connection: Keep-Alive\r\n";
1174
1175       if(!checkheaders(data, "User-Agent:") && data->set.useragent)
1176         useragent = conn->allocptr.uagent;
1177
1178       if(CURLE_OK == result) {
1179         /* Send the connect request to the proxy */
1180         /* BLOCKING */
1181         result =
1182           add_bufferf(req_buffer,
1183                       "CONNECT %s:%d HTTP/1.0\r\n"
1184                       "%s"  /* Host: */
1185                       "%s"  /* Proxy-Authorization */
1186                       "%s"  /* User-Agent */
1187                       "%s", /* Proxy-Connection */
1188                       hostname, remote_port,
1189                       host,
1190                       conn->allocptr.proxyuserpwd?
1191                       conn->allocptr.proxyuserpwd:"",
1192                       useragent,
1193                       proxyconn);
1194
1195         if(CURLE_OK == result)
1196           result = add_custom_headers(conn, req_buffer);
1197
1198         if(host && *host)
1199           free(host);
1200
1201         if(CURLE_OK == result)
1202           /* CRLF terminate the request */
1203           result = add_bufferf(req_buffer, "\r\n");
1204
1205         if(CURLE_OK == result)
1206           /* Now send off the request */
1207           result = add_buffer_send(req_buffer, conn,
1208                                    &data->info.request_size, 0, sockindex);
1209       }
1210       if(result)
1211         failf(data, "Failed sending CONNECT to proxy");
1212     }
1213     free(host_port);
1214     if(result)
1215       return result;
1216
1217     ptr=data->state.buffer;
1218     line_start = ptr;
1219
1220     nread=0;
1221     perline=0;
1222     keepon=TRUE;
1223
1224     while((nread<BUFSIZE) && (keepon && !error)) {
1225
1226       /* if timeout is requested, find out how much remaining time we have */
1227       long check = timeout - /* timeout time */
1228         Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
1229       if(check <=0 ) {
1230         failf(data, "Proxy CONNECT aborted due to timeout");
1231         error = SELECT_TIMEOUT; /* already too little time */
1232         break;
1233       }
1234
1235       /* timeout each second and check the timeout */
1236       switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD, 1000)) {
1237       case -1: /* select() error, stop reading */
1238         error = SELECT_ERROR;
1239         failf(data, "Proxy CONNECT aborted due to select() error");
1240         break;
1241       case 0: /* timeout */
1242         break;
1243       default:
1244         res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
1245         if(res< 0)
1246           /* EWOULDBLOCK */
1247           continue; /* go loop yourself */
1248         else if(res)
1249           keepon = FALSE;
1250         else if(gotbytes <= 0) {
1251           keepon = FALSE;
1252           error = SELECT_ERROR;
1253           failf(data, "Proxy CONNECT aborted");
1254         }
1255         else {
1256           /*
1257            * We got a whole chunk of data, which can be anything from one byte
1258            * to a set of lines and possibly just a piece of the last line.
1259            */
1260           int i;
1261
1262           nread += gotbytes;
1263
1264           if(keepon > TRUE) {
1265             /* This means we are currently ignoring a response-body, so we
1266                simply count down our counter and make sure to break out of the
1267                loop when we're done! */
1268             cl -= gotbytes;
1269             if(cl<=0) {
1270               keepon = FALSE;
1271               break;
1272             }
1273           }
1274           else
1275           for(i = 0; i < gotbytes; ptr++, i++) {
1276             perline++; /* amount of bytes in this line so far */
1277             if(*ptr=='\n') {
1278               char letter;
1279               int writetype;
1280
1281               /* output debug if that is requested */
1282               if(data->set.verbose)
1283                 Curl_debug(data, CURLINFO_HEADER_IN,
1284                            line_start, (size_t)perline, conn);
1285
1286               /* send the header to the callback */
1287               writetype = CLIENTWRITE_HEADER;
1288               if(data->set.include_header)
1289                 writetype |= CLIENTWRITE_BODY;
1290
1291               result = Curl_client_write(conn, writetype, line_start, perline);
1292               if(result)
1293                 return result;
1294
1295               /* Newlines are CRLF, so the CR is ignored as the line isn't
1296                  really terminated until the LF comes. Treat a following CR
1297                  as end-of-headers as well.*/
1298
1299               if(('\r' == line_start[0]) ||
1300                  ('\n' == line_start[0])) {
1301                 /* end of response-headers from the proxy */
1302                 if(cl && (407 == k->httpcode) && !data->state.authproblem) {
1303                   /* If we get a 407 response code with content length when we
1304                    * have no auth problem, we must ignore the whole
1305                    * response-body */
1306                   keepon = 2;
1307                   infof(data, "Ignore %" FORMAT_OFF_T
1308                         " bytes of response-body\n", cl);
1309                   cl -= (gotbytes - i);/* remove the remaining chunk of what
1310                                           we already read */
1311                   if(cl<=0)
1312                     /* if the whole thing was already read, we are done! */
1313                     keepon=FALSE;
1314                 }
1315                 else
1316                   keepon = FALSE;
1317                 break; /* breaks out of for-loop, not switch() */
1318               }
1319
1320               /* keep a backup of the position we are about to blank */
1321               letter = line_start[perline];
1322               line_start[perline]=0; /* zero terminate the buffer */
1323               if((checkprefix("WWW-Authenticate:", line_start) &&
1324                   (401 == k->httpcode)) ||
1325                  (checkprefix("Proxy-authenticate:", line_start) &&
1326                   (407 == k->httpcode))) {
1327                 result = Curl_http_input_auth(conn, k->httpcode, line_start);
1328                 if(result)
1329                   return result;
1330               }
1331               else if(checkprefix("Content-Length:", line_start)) {
1332                 cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
1333                                      NULL, 10);
1334               }
1335               else if(Curl_compareheader(line_start,
1336                                          "Connection:", "close"))
1337                 closeConnection = TRUE;
1338               else if(2 == sscanf(line_start, "HTTP/1.%d %d",
1339                                   &subversion,
1340                                   &k->httpcode)) {
1341                 /* store the HTTP code from the proxy */
1342                 data->info.httpproxycode = k->httpcode;
1343               }
1344               /* put back the letter we blanked out before */
1345               line_start[perline]= letter;
1346
1347               perline=0; /* line starts over here */
1348               line_start = ptr+1; /* this skips the zero byte we wrote */
1349             }
1350           }
1351         }
1352         break;
1353       } /* switch */
1354     } /* while there's buffer left and loop is requested */
1355
1356     if(error)
1357       return CURLE_RECV_ERROR;
1358
1359     if(data->info.httpproxycode != 200)
1360       /* Deal with the possibly already received authenticate
1361          headers. 'newurl' is set to a new URL if we must loop. */
1362       Curl_http_auth_act(conn);
1363
1364     if (closeConnection && data->reqdata.newurl) {
1365       /* Connection closed by server. Don't use it anymore */
1366       sclose(conn->sock[sockindex]);
1367       conn->sock[sockindex] = CURL_SOCKET_BAD;
1368       break;
1369     }
1370   } while(data->reqdata.newurl);
1371
1372   if(200 != k->httpcode) {
1373     failf(data, "Received HTTP code %d from proxy after CONNECT",
1374           k->httpcode);
1375
1376     if (closeConnection && data->reqdata.newurl)
1377       conn->bits.proxy_connect_closed = TRUE;
1378
1379     return CURLE_RECV_ERROR;
1380   }
1381
1382   /* If a proxy-authorization header was used for the proxy, then we should
1383      make sure that it isn't accidentally used for the document request
1384      after we've connected. So let's free and clear it here. */
1385   Curl_safefree(conn->allocptr.proxyuserpwd);
1386   conn->allocptr.proxyuserpwd = NULL;
1387
1388   data->state.authproxy.done = TRUE;
1389
1390   infof (data, "Proxy replied OK to CONNECT request\n");
1391   return CURLE_OK;
1392 }
1393
1394 /*
1395  * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1396  * the generic Curl_connect().
1397  */
1398 CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
1399 {
1400   struct SessionHandle *data;
1401   CURLcode result;
1402
1403   data=conn->data;
1404
1405   /* If we are not using a proxy and we want a secure connection, perform SSL
1406    * initialization & connection now.  If using a proxy with https, then we
1407    * must tell the proxy to CONNECT to the host we want to talk to.  Only
1408    * after the connect has occurred, can we start talking SSL
1409    */
1410
1411   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1412
1413     /* either SSL over proxy, or explicitly asked for */
1414     result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
1415                                conn->host.name,
1416                                conn->remote_port);
1417     if(CURLE_OK != result)
1418       return result;
1419   }
1420
1421   if(!data->state.this_is_a_follow) {
1422     /* this is not a followed location, get the original host name */
1423     if (data->state.first_host)
1424       /* Free to avoid leaking memory on multiple requests*/
1425       free(data->state.first_host);
1426
1427     data->state.first_host = strdup(conn->host.name);
1428     if(!data->state.first_host)
1429       return CURLE_OUT_OF_MEMORY;
1430   }
1431
1432   if(conn->protocol & PROT_HTTPS) {
1433     /* perform SSL initialization */
1434     if(data->state.used_interface == Curl_if_multi) {
1435       result = Curl_https_connecting(conn, done);
1436       if(result)
1437         return result;
1438     }
1439     else {
1440       /* BLOCKING */
1441       result = Curl_ssl_connect(conn, FIRSTSOCKET);
1442       if(result)
1443         return result;
1444       *done = TRUE;
1445     }
1446   }
1447   else {
1448     *done = TRUE;
1449   }
1450
1451   return CURLE_OK;
1452 }
1453
1454 CURLcode Curl_https_connecting(struct connectdata *conn, bool *done)
1455 {
1456   CURLcode result;
1457   curlassert(conn->protocol & PROT_HTTPS);
1458
1459   /* perform SSL initialization for this socket */
1460   result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
1461   if(result)
1462     return result;
1463
1464   return CURLE_OK;
1465 }
1466
1467 #ifdef USE_SSLEAY
1468 /* This function is OpenSSL-specific. It should be made to query the generic
1469    SSL layer instead. */
1470 int Curl_https_getsock(struct connectdata *conn,
1471                        curl_socket_t *socks,
1472                        int numsocks)
1473 {
1474   if (conn->protocol & PROT_HTTPS) {
1475     struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1476
1477     if(!numsocks)
1478       return GETSOCK_BLANK;
1479
1480     if (connssl->connecting_state == ssl_connect_2_writing) {
1481       /* write mode */
1482       socks[0] = conn->sock[FIRSTSOCKET];
1483       return GETSOCK_WRITESOCK(0);
1484     }
1485     else if (connssl->connecting_state == ssl_connect_2_reading) {
1486       /* read mode */
1487       socks[0] = conn->sock[FIRSTSOCKET];
1488       return GETSOCK_READSOCK(0);
1489     }
1490   }
1491   return CURLE_OK;
1492 }
1493 #else
1494 #ifdef USE_GNUTLS
1495 int Curl_https_getsock(struct connectdata *conn,
1496                        curl_socket_t *socks,
1497                        int numsocks)
1498 {
1499   (void)conn;
1500   (void)socks;
1501   (void)numsocks;
1502   return GETSOCK_BLANK;
1503 }
1504 #endif
1505 #endif
1506
1507 /*
1508  * Curl_http_done() gets called from Curl_done() after a single HTTP request
1509  * has been performed.
1510  */
1511
1512 CURLcode Curl_http_done(struct connectdata *conn,
1513                         CURLcode status, bool premature)
1514 {
1515   struct SessionHandle *data = conn->data;
1516   struct HTTP *http =data->reqdata.proto.http;
1517   struct Curl_transfer_keeper *k = &data->reqdata.keep;
1518   (void)premature; /* not used */
1519
1520   /* set the proper values (possibly modified on POST) */
1521   conn->fread = data->set.fread; /* restore */
1522   conn->fread_in = data->set.in; /* restore */
1523
1524   if (http == NULL)
1525     return CURLE_OK;
1526
1527   if(http->send_buffer) {
1528     send_buffer *buff = http->send_buffer;
1529
1530     free(buff->buffer);
1531     free(buff);
1532     http->send_buffer = NULL; /* clear the pointer */
1533   }
1534
1535   if(HTTPREQ_POST_FORM == data->set.httpreq) {
1536     k->bytecount = http->readbytecount + http->writebytecount;
1537
1538     Curl_formclean(&http->sendit); /* Now free that whole lot */
1539     if(http->form.fp) {
1540       /* a file being uploaded was left opened, close it! */
1541       fclose(http->form.fp);
1542       http->form.fp = NULL;
1543     }
1544   }
1545   else if(HTTPREQ_PUT == data->set.httpreq)
1546     k->bytecount = http->readbytecount + http->writebytecount;
1547
1548   if (status != CURLE_OK)
1549     return (status);
1550
1551   if(!conn->bits.retry &&
1552      ((http->readbytecount +
1553        conn->headerbytecount -
1554        conn->deductheadercount)) <= 0) {
1555     /* If this connection isn't simply closed to be retried, AND nothing was
1556        read from the HTTP server (that counts), this can't be right so we
1557        return an error here */
1558     failf(data, "Empty reply from server");
1559     return CURLE_GOT_NOTHING;
1560   }
1561
1562   return CURLE_OK;
1563 }
1564
1565 /* check and possibly add an Expect: header */
1566 static CURLcode expect100(struct SessionHandle *data,
1567                           send_buffer *req_buffer)
1568 {
1569   CURLcode result = CURLE_OK;
1570   data->state.expect100header = FALSE; /* default to false unless it is set
1571                                           to TRUE below */
1572   if((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
1573      !checkheaders(data, "Expect:")) {
1574     /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
1575        100-continue to the headers which actually speeds up post
1576        operations (as there is one packet coming back from the web
1577        server) */
1578     result = add_bufferf(req_buffer,
1579                          "Expect: 100-continue\r\n");
1580     if(result == CURLE_OK)
1581       data->state.expect100header = TRUE;
1582   }
1583   return result;
1584 }
1585
1586 static CURLcode add_custom_headers(struct connectdata *conn,
1587                                    send_buffer *req_buffer)
1588 {
1589   CURLcode result = CURLE_OK;
1590   char *ptr;
1591   struct curl_slist *headers=conn->data->set.headers;
1592
1593   while(headers) {
1594     ptr = strchr(headers->data, ':');
1595     if(ptr) {
1596       /* we require a colon for this to be a true header */
1597
1598       ptr++; /* pass the colon */
1599       while(*ptr && ISSPACE(*ptr))
1600         ptr++;
1601
1602       if(*ptr) {
1603         /* only send this if the contents was non-blank */
1604
1605         if(conn->allocptr.host &&
1606            /* a Host: header was sent already, don't pass on any custom Host:
1607               header as that will produce *two* in the same request! */
1608            curl_strnequal("Host:", headers->data, 5))
1609           ;
1610         else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
1611                 /* this header (extended by formdata.c) is sent later */
1612                 curl_strnequal("Content-Type:", headers->data,
1613                                strlen("Content-Type:")))
1614           ;
1615         else {
1616           result = add_bufferf(req_buffer, "%s\r\n", headers->data);
1617           if(result)
1618             return result;
1619         }
1620       }
1621     }
1622     headers = headers->next;
1623   }
1624   return result;
1625 }
1626
1627 /*
1628  * Curl_http() gets called from the generic Curl_do() function when a HTTP
1629  * request is to be performed. This creates and sends a properly constructed
1630  * HTTP request.
1631  */
1632 CURLcode Curl_http(struct connectdata *conn, bool *done)
1633 {
1634   struct SessionHandle *data=conn->data;
1635   char *buf = data->state.buffer; /* this is a short cut to the buffer */
1636   CURLcode result=CURLE_OK;
1637   struct HTTP *http;
1638   char *ppath = data->reqdata.path;
1639   char *host = conn->host.name;
1640   const char *te = ""; /* transfer-encoding */
1641   char *ptr;
1642   char *request;
1643   Curl_HttpReq httpreq = data->set.httpreq;
1644   char *addcookies = NULL;
1645   curl_off_t included_body = 0;
1646
1647   /* Always consider the DO phase done after this function call, even if there
1648      may be parts of the request that is not yet sent, since we can deal with
1649      the rest of the request in the PERFORM phase. */
1650   *done = TRUE;
1651
1652   if(!data->reqdata.proto.http) {
1653     /* Only allocate this struct if we don't already have it! */
1654
1655     http = (struct HTTP *)malloc(sizeof(struct HTTP));
1656     if(!http)
1657       return CURLE_OUT_OF_MEMORY;
1658     memset(http, 0, sizeof(struct HTTP));
1659     data->reqdata.proto.http = http;
1660   }
1661   else
1662     http = data->reqdata.proto.http;
1663
1664   /* We default to persistent connections */
1665   conn->bits.close = FALSE;
1666
1667   if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
1668        data->set.upload) {
1669     httpreq = HTTPREQ_PUT;
1670   }
1671
1672   /* Now set the 'request' pointer to the proper request string */
1673   if(data->set.customrequest)
1674     request = data->set.customrequest;
1675   else {
1676     if(conn->bits.no_body)
1677       request = (char *)"HEAD";
1678     else {
1679       curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
1680       switch(httpreq) {
1681       case HTTPREQ_POST:
1682       case HTTPREQ_POST_FORM:
1683         request = (char *)"POST";
1684         break;
1685       case HTTPREQ_PUT:
1686         request = (char *)"PUT";
1687         break;
1688       default: /* this should never happen */
1689       case HTTPREQ_GET:
1690         request = (char *)"GET";
1691         break;
1692       case HTTPREQ_HEAD:
1693         request = (char *)"HEAD";
1694         break;
1695       }
1696     }
1697   }
1698
1699   /* The User-Agent string might have been allocated in url.c already, because
1700      it might have been used in the proxy connect, but if we have got a header
1701      with the user-agent string specified, we erase the previously made string
1702      here. */
1703   if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
1704     free(conn->allocptr.uagent);
1705     conn->allocptr.uagent=NULL;
1706   }
1707
1708   /* setup the authentication headers */
1709   result = Curl_http_output_auth(conn, request, ppath, FALSE);
1710   if(result)
1711     return result;
1712
1713   if((data->state.authhost.multi || data->state.authproxy.multi) &&
1714      (httpreq != HTTPREQ_GET) &&
1715      (httpreq != HTTPREQ_HEAD)) {
1716     /* Auth is required and we are not authenticated yet. Make a PUT or POST
1717        with content-length zero as a "probe". */
1718     conn->bits.authneg = TRUE;
1719   }
1720   else
1721     conn->bits.authneg = FALSE;
1722
1723   Curl_safefree(conn->allocptr.ref);
1724   if(data->change.referer && !checkheaders(data, "Referer:"))
1725     conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
1726   else
1727     conn->allocptr.ref = NULL;
1728
1729   if(data->set.cookie && !checkheaders(data, "Cookie:"))
1730     addcookies = data->set.cookie;
1731
1732   if(!checkheaders(data, "Accept-Encoding:") &&
1733      data->set.encoding) {
1734     Curl_safefree(conn->allocptr.accept_encoding);
1735     conn->allocptr.accept_encoding =
1736       aprintf("Accept-Encoding: %s\r\n", data->set.encoding);
1737     if(!conn->allocptr.accept_encoding)
1738       return CURLE_OUT_OF_MEMORY;
1739   }
1740
1741   ptr = checkheaders(data, "Transfer-Encoding:");
1742   if(ptr) {
1743     /* Some kind of TE is requested, check if 'chunked' is chosen */
1744     conn->bits.upload_chunky =
1745       Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
1746   }
1747   else {
1748     if (httpreq == HTTPREQ_GET)
1749       conn->bits.upload_chunky = FALSE;
1750     if(conn->bits.upload_chunky)
1751       te = "Transfer-Encoding: chunked\r\n";
1752   }
1753
1754   Curl_safefree(conn->allocptr.host);
1755
1756   ptr = checkheaders(data, "Host:");
1757   if(ptr && (!data->state.this_is_a_follow ||
1758              curl_strequal(data->state.first_host, conn->host.name))) {
1759 #if !defined(CURL_DISABLE_COOKIES)
1760     /* If we have a given custom Host: header, we extract the host name in
1761        order to possibly use it for cookie reasons later on. We only allow the
1762        custom Host: header if this is NOT a redirect, as setting Host: in the
1763        redirected request is being out on thin ice. Except if the host name
1764        is the same as the first one! */
1765     char *start = ptr+strlen("Host:");
1766     while(*start && ISSPACE(*start ))
1767       start++;
1768     ptr = start; /* start host-scanning here */
1769
1770     /* scan through the string to find the end (space or colon) */
1771     while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr))
1772       ptr++;
1773
1774     if(ptr != start) {
1775       size_t len=ptr-start;
1776       Curl_safefree(conn->allocptr.cookiehost);
1777       conn->allocptr.cookiehost = malloc(len+1);
1778       if(!conn->allocptr.cookiehost)
1779         return CURLE_OUT_OF_MEMORY;
1780       memcpy(conn->allocptr.cookiehost, start, len);
1781       conn->allocptr.cookiehost[len]=0;
1782     }
1783 #endif
1784
1785     conn->allocptr.host = NULL;
1786   }
1787   else {
1788     /* When building Host: headers, we must put the host name within
1789        [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
1790
1791     if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
1792        (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
1793       /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
1794          the port number in the host string */
1795       conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
1796                                     conn->bits.ipv6_ip?"[":"",
1797                                     host,
1798                                     conn->bits.ipv6_ip?"]":"");
1799     else
1800       conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
1801                                     conn->bits.ipv6_ip?"[":"",
1802                                     host,
1803                                     conn->bits.ipv6_ip?"]":"",
1804                                     conn->remote_port);
1805
1806     if(!conn->allocptr.host)
1807       /* without Host: we can't make a nice request */
1808       return CURLE_OUT_OF_MEMORY;
1809   }
1810
1811   if (conn->bits.httpproxy && !conn->bits.tunnel_proxy)  {
1812     /* Using a proxy but does not tunnel through it */
1813
1814     /* The path sent to the proxy is in fact the entire URL. But if the remote
1815        host is a IDN-name, we must make sure that the request we produce only
1816        uses the encoded host name! */
1817     if(conn->host.dispname != conn->host.name) {
1818       char *url = data->change.url;
1819       ptr = strstr(url, conn->host.dispname);
1820       if(ptr) {
1821         /* This is where the display name starts in the URL, now replace this
1822            part with the encoded name. TODO: This method of replacing the host
1823            name is rather crude as I believe there's a slight risk that the
1824            user has entered a user name or password that contain the host name
1825            string. */
1826         size_t currlen = strlen(conn->host.dispname);
1827         size_t newlen = strlen(conn->host.name);
1828         size_t urllen = strlen(url);
1829
1830         char *newurl;
1831
1832         newurl = malloc(urllen + newlen - currlen + 1);
1833         if(newurl) {
1834           /* copy the part before the host name */
1835           memcpy(newurl, url, ptr - url);
1836           /* append the new host name instead of the old */
1837           memcpy(newurl + (ptr - url), conn->host.name, newlen);
1838           /* append the piece after the host name */
1839           memcpy(newurl + newlen + (ptr - url),
1840                  ptr + currlen, /* copy the trailing zero byte too */
1841                  urllen - (ptr-url) - currlen + 1);
1842           if(data->change.url_alloc)
1843             free(data->change.url);
1844           data->change.url = newurl;
1845           data->change.url_alloc = TRUE;
1846         }
1847         else
1848           return CURLE_OUT_OF_MEMORY;
1849       }
1850     }
1851     ppath = data->change.url;
1852   }
1853   if(HTTPREQ_POST_FORM == httpreq) {
1854     /* we must build the whole darned post sequence first, so that we have
1855        a size of the whole shebang before we start to send it */
1856      result = Curl_getFormData(&http->sendit, data->set.httppost,
1857                                checkheaders(data, "Content-Type:"),
1858                                &http->postsize);
1859      if(CURLE_OK != result) {
1860        /* Curl_getFormData() doesn't use failf() */
1861        failf(data, "failed creating formpost data");
1862        return result;
1863      }
1864   }
1865
1866
1867   http->p_pragma =
1868     (!checkheaders(data, "Pragma:") &&
1869      (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )?
1870     "Pragma: no-cache\r\n":NULL;
1871
1872   if(!checkheaders(data, "Accept:"))
1873     http->p_accept = "Accept: */*\r\n";
1874
1875   if(( (HTTPREQ_POST == httpreq) ||
1876        (HTTPREQ_POST_FORM == httpreq) ||
1877        (HTTPREQ_PUT == httpreq) ) &&
1878      data->reqdata.resume_from) {
1879     /**********************************************************************
1880      * Resuming upload in HTTP means that we PUT or POST and that we have
1881      * got a resume_from value set. The resume value has already created
1882      * a Range: header that will be passed along. We need to "fast forward"
1883      * the file the given number of bytes and decrease the assume upload
1884      * file size before we continue this venture in the dark lands of HTTP.
1885      *********************************************************************/
1886
1887     if(data->reqdata.resume_from < 0 ) {
1888       /*
1889        * This is meant to get the size of the present remote-file by itself.
1890        * We don't support this now. Bail out!
1891        */
1892        data->reqdata.resume_from = 0;
1893     }
1894
1895     if(data->reqdata.resume_from) {
1896       /* do we still game? */
1897       curl_off_t passed=0;
1898
1899       /* Now, let's read off the proper amount of bytes from the
1900          input. If we knew it was a proper file we could've just
1901          fseek()ed but we only have a stream here */
1902       do {
1903         size_t readthisamountnow = (size_t)(data->reqdata.resume_from - passed);
1904         size_t actuallyread;
1905
1906         if(readthisamountnow > BUFSIZE)
1907           readthisamountnow = BUFSIZE;
1908
1909         actuallyread =
1910           data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
1911                           data->set.in);
1912
1913         passed += actuallyread;
1914         if(actuallyread != readthisamountnow) {
1915           failf(data, "Could only read %" FORMAT_OFF_T
1916                 " bytes from the input",
1917                 passed);
1918           return CURLE_READ_ERROR;
1919         }
1920       } while(passed != data->reqdata.resume_from); /* loop until done */
1921
1922       /* now, decrease the size of the read */
1923       if(data->set.infilesize>0) {
1924         data->set.infilesize -= data->reqdata.resume_from;
1925
1926         if(data->set.infilesize <= 0) {
1927           failf(data, "File already completely uploaded");
1928           return CURLE_PARTIAL_FILE;
1929         }
1930       }
1931       /* we've passed, proceed as normal */
1932     }
1933   }
1934   if(data->reqdata.use_range) {
1935     /*
1936      * A range is selected. We use different headers whether we're downloading
1937      * or uploading and we always let customized headers override our internal
1938      * ones if any such are specified.
1939      */
1940     if((httpreq == HTTPREQ_GET) &&
1941        !checkheaders(data, "Range:")) {
1942       /* if a line like this was already allocated, free the previous one */
1943       if(conn->allocptr.rangeline)
1944         free(conn->allocptr.rangeline);
1945       conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->reqdata.range);
1946     }
1947     else if((httpreq != HTTPREQ_GET) &&
1948             !checkheaders(data, "Content-Range:")) {
1949
1950       if(data->reqdata.resume_from) {
1951         /* This is because "resume" was selected */
1952         curl_off_t total_expected_size=
1953           data->reqdata.resume_from + data->set.infilesize;
1954         conn->allocptr.rangeline =
1955             aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
1956                     "/%" FORMAT_OFF_T "\r\n",
1957                     data->reqdata.range, total_expected_size-1,
1958                     total_expected_size);
1959       }
1960       else {
1961         /* Range was selected and then we just pass the incoming range and
1962            append total size */
1963         conn->allocptr.rangeline =
1964             aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
1965                     data->reqdata.range, data->set.infilesize);
1966       }
1967     }
1968   }
1969
1970   {
1971     /* Use 1.1 unless the use specificly asked for 1.0 */
1972     const char *httpstring=
1973       data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
1974
1975     send_buffer *req_buffer;
1976     curl_off_t postsize; /* off_t type to be able to hold a large file size */
1977
1978     /* initialize a dynamic send-buffer */
1979     req_buffer = add_buffer_init();
1980
1981     if(!req_buffer)
1982       return CURLE_OUT_OF_MEMORY;
1983
1984     /* add the main request stuff */
1985     result =
1986       add_bufferf(req_buffer,
1987                   "%s " /* GET/HEAD/POST/PUT */
1988                   "%s HTTP/%s\r\n" /* path + HTTP version */
1989                   "%s" /* proxyuserpwd */
1990                   "%s" /* userpwd */
1991                   "%s" /* range */
1992                   "%s" /* user agent */
1993                   "%s" /* host */
1994                   "%s" /* pragma */
1995                   "%s" /* accept */
1996                   "%s" /* accept-encoding */
1997                   "%s" /* referer */
1998                   "%s" /* Proxy-Connection */
1999                   "%s",/* transfer-encoding */
2000
2001                 request,
2002                 ppath,
2003                 httpstring,
2004                 conn->allocptr.proxyuserpwd?
2005                 conn->allocptr.proxyuserpwd:"",
2006                 conn->allocptr.userpwd?conn->allocptr.userpwd:"",
2007                 (data->reqdata.use_range && conn->allocptr.rangeline)?
2008                 conn->allocptr.rangeline:"",
2009                 (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
2010                 conn->allocptr.uagent:"",
2011                 (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
2012                 http->p_pragma?http->p_pragma:"",
2013                 http->p_accept?http->p_accept:"",
2014                 (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
2015                 conn->allocptr.accept_encoding:"",
2016                 (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> */,
2017                 (conn->bits.httpproxy &&
2018                  !conn->bits.tunnel_proxy &&
2019                  !checkheaders(data, "Proxy-Connection:"))?
2020                   "Proxy-Connection: Keep-Alive\r\n":"",
2021                 te
2022                 );
2023
2024     if(result)
2025       return result;
2026
2027 #if !defined(CURL_DISABLE_COOKIES)
2028     if(data->cookies || addcookies) {
2029       struct Cookie *co=NULL; /* no cookies from start */
2030       int count=0;
2031
2032       if(data->cookies) {
2033         Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2034         co = Curl_cookie_getlist(data->cookies,
2035                                  conn->allocptr.cookiehost?
2036                                  conn->allocptr.cookiehost:host, data->reqdata.path,
2037                                  (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
2038         Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2039       }
2040       if(co) {
2041         struct Cookie *store=co;
2042         /* now loop through all cookies that matched */
2043         while(co) {
2044           if(co->value) {
2045             if(0 == count) {
2046               result = add_bufferf(req_buffer, "Cookie: ");
2047               if(result)
2048                 break;
2049             }
2050             result = add_bufferf(req_buffer,
2051                                  "%s%s=%s", count?"; ":"",
2052                                  co->name, co->value);
2053             if(result)
2054               break;
2055             count++;
2056           }
2057           co = co->next; /* next cookie please */
2058         }
2059         Curl_cookie_freelist(store); /* free the cookie list */
2060       }
2061       if(addcookies && (CURLE_OK == result)) {
2062         if(!count)
2063           result = add_bufferf(req_buffer, "Cookie: ");
2064         if(CURLE_OK == result) {
2065           result = add_bufferf(req_buffer, "%s%s",
2066                                count?"; ":"",
2067                                addcookies);
2068           count++;
2069         }
2070       }
2071       if(count && (CURLE_OK == result))
2072         result = add_buffer(req_buffer, "\r\n", 2);
2073
2074       if(result)
2075         return result;
2076     }
2077 #endif
2078
2079     if(data->set.timecondition) {
2080       struct tm *tm;
2081
2082       /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
2083        * header family should have their times set in GMT as RFC2616 defines:
2084        * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
2085        * (GMT), without exception. For the purposes of HTTP, GMT is exactly
2086        * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
2087        */
2088
2089 #ifdef HAVE_GMTIME_R
2090       /* thread-safe version */
2091       struct tm keeptime;
2092       tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
2093 #else
2094       tm = gmtime(&data->set.timevalue);
2095 #endif
2096
2097       /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
2098       snprintf(buf, BUFSIZE-1,
2099                "%s, %02d %s %4d %02d:%02d:%02d GMT",
2100                Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2101                tm->tm_mday,
2102                Curl_month[tm->tm_mon],
2103                tm->tm_year + 1900,
2104                tm->tm_hour,
2105                tm->tm_min,
2106                tm->tm_sec);
2107
2108       switch(data->set.timecondition) {
2109       case CURL_TIMECOND_IFMODSINCE:
2110       default:
2111         result = add_bufferf(req_buffer,
2112                              "If-Modified-Since: %s\r\n", buf);
2113         break;
2114       case CURL_TIMECOND_IFUNMODSINCE:
2115         result = add_bufferf(req_buffer,
2116                              "If-Unmodified-Since: %s\r\n", buf);
2117         break;
2118       case CURL_TIMECOND_LASTMOD:
2119         result = add_bufferf(req_buffer,
2120                              "Last-Modified: %s\r\n", buf);
2121         break;
2122       }
2123       if(result)
2124         return result;
2125     }
2126
2127     result = add_custom_headers(conn, req_buffer);
2128     if(result)
2129       return result;
2130
2131     http->postdata = NULL;  /* nothing to post at this point */
2132     Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
2133
2134     /* If 'authdone' is FALSE, we must not set the write socket index to the
2135        Curl_transfer() call below, as we're not ready to actually upload any
2136        data yet. */
2137
2138     switch(httpreq) {
2139
2140     case HTTPREQ_POST_FORM:
2141       if(!http->sendit || conn->bits.authneg) {
2142         /* nothing to post! */
2143         result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
2144         if(result)
2145           return result;
2146
2147         result = add_buffer_send(req_buffer, conn,
2148                                  &data->info.request_size, 0, FIRSTSOCKET);
2149         if(result)
2150           failf(data, "Failed sending POST request");
2151         else
2152           /* setup variables for the upcoming transfer */
2153           result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2154                                        &http->readbytecount,
2155                                        -1, NULL);
2156         break;
2157       }
2158
2159       if(Curl_FormInit(&http->form, http->sendit)) {
2160         failf(data, "Internal HTTP POST error!");
2161         return CURLE_HTTP_POST_ERROR;
2162       }
2163
2164       /* set the read function to read from the generated form data */
2165       conn->fread = (curl_read_callback)Curl_FormReader;
2166       conn->fread_in = &http->form;
2167
2168       http->sending = HTTPSEND_BODY;
2169
2170       if(!conn->bits.upload_chunky) {
2171         /* only add Content-Length if not uploading chunked */
2172         result = add_bufferf(req_buffer,
2173                              "Content-Length: %" FORMAT_OFF_T "\r\n",
2174                              http->postsize);
2175         if(result)
2176           return result;
2177       }
2178
2179       result = expect100(data, req_buffer);
2180       if(result)
2181         return result;
2182
2183       {
2184
2185         /* Get Content-Type: line from Curl_formpostheader.
2186         */
2187         char *contentType;
2188         size_t linelength=0;
2189         contentType = Curl_formpostheader((void *)&http->form,
2190                                           &linelength);
2191         if(!contentType) {
2192           failf(data, "Could not get Content-Type header line!");
2193           return CURLE_HTTP_POST_ERROR;
2194         }
2195
2196         result = add_buffer(req_buffer, contentType, linelength);
2197         if(result)
2198           return result;
2199       }
2200
2201       /* make the request end in a true CRLF */
2202       result = add_buffer(req_buffer, "\r\n", 2);
2203       if(result)
2204         return result;
2205
2206       /* set upload size to the progress meter */
2207       Curl_pgrsSetUploadSize(data, http->postsize);
2208
2209       /* fire away the whole request to the server */
2210       result = add_buffer_send(req_buffer, conn,
2211                                &data->info.request_size, 0, FIRSTSOCKET);
2212       if(result)
2213         failf(data, "Failed sending POST request");
2214       else
2215         /* setup variables for the upcoming transfer */
2216         result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2217                                      &http->readbytecount,
2218                                      FIRSTSOCKET,
2219                                      &http->writebytecount);
2220
2221       if(result) {
2222         Curl_formclean(&http->sendit); /* free that whole lot */
2223         return result;
2224       }
2225 #ifdef CURL_DOES_CONVERSIONS
2226 /* time to convert the form data... */
2227       result = Curl_formconvert(data, http->sendit);
2228       if(result) {
2229         Curl_formclean(&http->sendit); /* free that whole lot */
2230         return result;
2231       }
2232 #endif /* CURL_DOES_CONVERSIONS */
2233       break;
2234
2235     case HTTPREQ_PUT: /* Let's PUT the data to the server! */
2236
2237       if(conn->bits.authneg)
2238         postsize = 0;
2239       else
2240         postsize = data->set.infilesize;
2241
2242       if((postsize != -1) && !conn->bits.upload_chunky) {
2243         /* only add Content-Length if not uploading chunked */
2244         result = add_bufferf(req_buffer,
2245                              "Content-Length: %" FORMAT_OFF_T "\r\n",
2246                              postsize );
2247         if(result)
2248           return result;
2249       }
2250
2251       result = expect100(data, req_buffer);
2252       if(result)
2253         return result;
2254
2255       result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
2256       if(result)
2257         return result;
2258
2259       /* set the upload size to the progress meter */
2260       Curl_pgrsSetUploadSize(data, postsize);
2261
2262       /* this sends the buffer and frees all the buffer resources */
2263       result = add_buffer_send(req_buffer, conn,
2264                                &data->info.request_size, 0, FIRSTSOCKET);
2265       if(result)
2266         failf(data, "Failed sending PUT request");
2267       else
2268         /* prepare for transfer */
2269         result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2270                                      &http->readbytecount,
2271                                      postsize?FIRSTSOCKET:-1,
2272                                      postsize?&http->writebytecount:NULL);
2273       if(result)
2274         return result;
2275       break;
2276
2277     case HTTPREQ_POST:
2278       /* this is the simple POST, using x-www-form-urlencoded style */
2279
2280       if(conn->bits.authneg)
2281         postsize = 0;
2282       else
2283         /* figure out the size of the postfields */
2284         postsize = (data->set.postfieldsize != -1)?
2285           data->set.postfieldsize:
2286           (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
2287
2288       if(!conn->bits.upload_chunky) {
2289         /* We only set Content-Length and allow a custom Content-Length if
2290            we don't upload data chunked, as RFC2616 forbids us to set both
2291            kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2292
2293         if(!checkheaders(data, "Content-Length:")) {
2294           /* we allow replacing this header, although it isn't very wise to
2295              actually set your own */
2296           result = add_bufferf(req_buffer,
2297                                "Content-Length: %" FORMAT_OFF_T"\r\n",
2298                                postsize);
2299           if(result)
2300             return result;
2301         }
2302       }
2303
2304       if(!checkheaders(data, "Content-Type:")) {
2305         result = add_bufferf(req_buffer,
2306                              "Content-Type: application/x-www-form-urlencoded\r\n");
2307         if(result)
2308           return result;
2309       }
2310
2311       if(data->set.postfields) {
2312
2313         /* for really small posts we don't use Expect: headers at all, and for
2314            the somewhat bigger ones we allow the app to disable it */
2315         if(postsize > TINY_INITIAL_POST_SIZE) {
2316           result = expect100(data, req_buffer);
2317           if(result)
2318             return result;
2319         }
2320         else
2321           data->state.expect100header = FALSE;
2322
2323         if(!data->state.expect100header &&
2324            (postsize < MAX_INITIAL_POST_SIZE))  {
2325           /* if we don't use expect:-100  AND
2326              postsize is less than MAX_INITIAL_POST_SIZE
2327
2328              then append the post data to the HTTP request header. This limit
2329              is no magic limit but only set to prevent really huge POSTs to
2330              get the data duplicated with malloc() and family. */
2331
2332           result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2333           if(result)
2334             return result;
2335
2336           if(!conn->bits.upload_chunky) {
2337             /* We're not sending it 'chunked', append it to the request
2338                already now to reduce the number if send() calls */
2339             result = add_buffer(req_buffer, data->set.postfields,
2340                                 (size_t)postsize);
2341             included_body = postsize;
2342           }
2343           else {
2344             /* Append the POST data chunky-style */
2345             result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2346             if(CURLE_OK == result)
2347               result = add_buffer(req_buffer, data->set.postfields,
2348                                   (size_t)postsize);
2349             if(CURLE_OK == result)
2350               result = add_buffer(req_buffer,
2351                                   "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2352                                   /* CR  LF   0  CR  LF  CR  LF */
2353             included_body = postsize + 7;
2354           }
2355           if(result)
2356             return result;
2357         }
2358         else {
2359           /* A huge POST coming up, do data separate from the request */
2360           http->postsize = postsize;
2361           http->postdata = data->set.postfields;
2362
2363           http->sending = HTTPSEND_BODY;
2364
2365           conn->fread = (curl_read_callback)readmoredata;
2366           conn->fread_in = (void *)conn;
2367
2368           /* set the upload size to the progress meter */
2369           Curl_pgrsSetUploadSize(data, http->postsize);
2370
2371           add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2372         }
2373       }
2374       else {
2375         add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2376
2377         if(data->set.postfieldsize) {
2378           /* set the upload size to the progress meter */
2379           Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2380
2381           /* set the pointer to mark that we will send the post body using
2382              the read callback */
2383           http->postdata = (char *)&http->postdata;
2384         }
2385       }
2386       /* issue the request */
2387       result = add_buffer_send(req_buffer, conn, &data->info.request_size,
2388                                (size_t)included_body, FIRSTSOCKET);
2389
2390       if(result)
2391         failf(data, "Failed sending HTTP POST request");
2392       else
2393         result =
2394           Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2395                         &http->readbytecount,
2396                         http->postdata?FIRSTSOCKET:-1,
2397                         http->postdata?&http->writebytecount:NULL);
2398       break;
2399
2400     default:
2401       add_buffer(req_buffer, "\r\n", 2);
2402
2403       /* issue the request */
2404       result = add_buffer_send(req_buffer, conn,
2405                                &data->info.request_size, 0, FIRSTSOCKET);
2406
2407       if(result)
2408         failf(data, "Failed sending HTTP request");
2409       else
2410         /* HTTP GET/HEAD download: */
2411         result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2412                                &http->readbytecount,
2413                                http->postdata?FIRSTSOCKET:-1,
2414                                http->postdata?&http->writebytecount:NULL);
2415     }
2416     if(result)
2417       return result;
2418   }
2419
2420   return CURLE_OK;
2421 }
2422 #endif