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