~ubuntu-branches/ubuntu/vivid/curl/vivid

« back to all changes in this revision

Viewing changes to lib/http.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Schuldei
  • Date: 2009-04-02 23:35:45 UTC
  • mto: (1.2.1 upstream) (3.2.3 sid)
  • mto: This revision was merged to the branch mainline in revision 38.
  • Revision ID: james.westby@ubuntu.com-20090402233545-geixkwhe3izccjt7
Tags: upstream-7.19.4
ImportĀ upstreamĀ versionĀ 7.19.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: http.c,v 1.371 2008-05-19 20:57:28 bagder Exp $
 
21
 * $Id: http.c,v 1.412 2009-02-24 08:30:09 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
66
66
#ifdef HAVE_SYS_IOCTL_H
67
67
#include <sys/ioctl.h>
68
68
#endif
69
 
#include <signal.h>
70
69
 
71
70
#ifdef HAVE_SYS_PARAM_H
72
71
#include <sys/param.h>
81
80
#include "easyif.h" /* for Curl_convert_... prototypes */
82
81
#include "formdata.h"
83
82
#include "progress.h"
84
 
#include "base64.h"
 
83
#include "curl_base64.h"
85
84
#include "cookie.h"
86
85
#include "strequal.h"
87
86
#include "sslgen.h"
97
96
#include "parsedate.h" /* for the week day and month names */
98
97
#include "strtoofft.h"
99
98
#include "multiif.h"
 
99
#include "rawstr.h"
100
100
 
101
101
#define _MPRINTF_REPLACE /* use our functions only */
102
102
#include <curl/mprintf.h>
114
114
static int http_getsock_do(struct connectdata *conn,
115
115
                           curl_socket_t *socks,
116
116
                           int numsocks);
 
117
#ifdef USE_SSL
117
118
static CURLcode https_connecting(struct connectdata *conn, bool *done);
118
 
#ifdef USE_SSL
119
119
static int https_getsock(struct connectdata *conn,
120
120
                         curl_socket_t *socks,
121
121
                         int numsocks);
 
122
#else
 
123
#define https_connecting(x,y) CURLE_COULDNT_CONNECT
122
124
#endif
123
125
 
124
126
/*
135
137
  ZERO_NULL,                            /* doing */
136
138
  ZERO_NULL,                            /* proto_getsock */
137
139
  http_getsock_do,                      /* doing_getsock */
 
140
  ZERO_NULL,                            /* perform_getsock */
138
141
  ZERO_NULL,                            /* disconnect */
139
142
  PORT_HTTP,                            /* defport */
140
143
  PROT_HTTP,                            /* protocol */
155
158
  ZERO_NULL,                            /* doing */
156
159
  https_getsock,                        /* proto_getsock */
157
160
  http_getsock_do,                      /* doing_getsock */
 
161
  ZERO_NULL,                            /* perform_getsock */
158
162
  ZERO_NULL,                            /* disconnect */
159
163
  PORT_HTTPS,                           /* defport */
160
164
  PROT_HTTP | PROT_HTTPS | PROT_SSL     /* protocol */
174
178
  size_t thislen = strlen(thisheader);
175
179
 
176
180
  for(head = data->set.headers; head; head=head->next) {
177
 
    if(strnequal(head->data, thisheader, thislen))
 
181
    if(Curl_raw_nequal(head->data, thisheader, thislen))
178
182
      return head->data;
179
183
  }
180
184
  return NULL;
181
185
}
182
186
 
183
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
 */
 
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
/*
184
243
 * http_output_basic() sets up an Authorization: header (or the proxy version)
185
244
 * for HTTP Basic authentication.
186
245
 *
191
250
  char *authorization;
192
251
  struct SessionHandle *data=conn->data;
193
252
  char **userp;
194
 
  char *user;
195
 
  char *pwd;
 
253
  const char *user;
 
254
  const char *pwd;
196
255
 
197
256
  if(proxy) {
198
257
    userp = &conn->allocptr.proxyuserpwd;
236
295
  picked = TRUE;
237
296
 
238
297
  /* The order of these checks is highly relevant, as this will be the order
239
 
     of preference in case of the existance of multiple accepted types. */
 
298
     of preference in case of the existence of multiple accepted types. */
240
299
  if(avail & CURLAUTH_GSSNEGOTIATE)
241
300
    pick->picked = CURLAUTH_GSSNEGOTIATE;
242
301
  else if(avail & CURLAUTH_DIGEST)
255
314
}
256
315
 
257
316
/*
258
 
 * perhapsrewind()
 
317
 * Curl_http_perhapsrewind()
259
318
 *
260
319
 * If we are doing POST or PUT {
261
320
 *   If we have more data to send {
277
336
 *   }
278
337
 * }
279
338
 */
280
 
static CURLcode perhapsrewind(struct connectdata *conn)
 
339
CURLcode Curl_http_perhapsrewind(struct connectdata *conn)
281
340
{
282
341
  struct SessionHandle *data = conn->data;
283
342
  struct HTTP *http = data->state.proto.http;
284
343
  curl_off_t bytessent;
285
344
  curl_off_t expectsend = -1; /* default is unknown */
286
345
 
287
 
  if(!http)
 
346
  if(!http || !(conn->protocol & PROT_HTTP))
288
347
    /* If this is still NULL, we have not reach very far and we can
289
 
       safely skip this rewinding stuff */
290
 
    return CURLE_OK;
 
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
  }
291
359
 
292
360
  bytessent = http->writebytecount;
293
361
 
356
424
}
357
425
 
358
426
/*
359
 
 * Curl_http_auth_act() gets called when a all HTTP headers have been received
 
427
 * Curl_http_auth_act() gets called when all HTTP headers have been received
360
428
 * and it checks what authentication methods that are available and decides
361
 
 * which one (if any) to use. It will set 'newurl' if an auth metod was
 
429
 * which one (if any) to use. It will set 'newurl' if an auth method was
362
430
 * picked.
363
431
 */
364
432
 
369
437
  bool pickproxy = FALSE;
370
438
  CURLcode code = CURLE_OK;
371
439
 
372
 
  if(100 == data->req.httpcode)
 
440
  if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
373
441
    /* this is a transient response code, ignore */
374
442
    return CURLE_OK;
375
443
 
392
460
  }
393
461
 
394
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);
395
467
    data->req.newurl = strdup(data->change.url); /* clone URL */
396
468
    if(!data->req.newurl)
397
469
      return CURLE_OUT_OF_MEMORY;
399
471
    if((data->set.httpreq != HTTPREQ_GET) &&
400
472
       (data->set.httpreq != HTTPREQ_HEAD) &&
401
473
       !conn->bits.rewindaftersend) {
402
 
      code = perhapsrewind(conn);
 
474
      code = Curl_http_perhapsrewind(conn);
403
475
      if(code)
404
476
        return code;
405
477
    }
429
501
  return code;
430
502
}
431
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
 
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
 
432
591
/**
433
592
 * Curl_http_output_auth() setups the authentication headers for the
434
593
 * host/proxy and the correct authentication
452
611
{
453
612
  CURLcode result = CURLE_OK;
454
613
  struct SessionHandle *data = conn->data;
455
 
  const char *auth=NULL;
456
614
  struct auth *authhost;
457
615
  struct auth *authproxy;
458
616
 
482
640
       and if this is one single bit it'll be used instantly. */
483
641
    authproxy->picked = authproxy->want;
484
642
 
 
643
#ifndef CURL_DISABLE_PROXY
485
644
  /* Send proxy authentication header if needed */
486
645
  if(conn->bits.httpproxy &&
487
646
      (conn->bits.tunnel_proxy == proxytunnel)) {
488
 
#ifdef HAVE_GSSAPI
489
 
    if((authproxy->picked == CURLAUTH_GSSNEGOTIATE) &&
490
 
       data->state.negotiate.context &&
491
 
       !GSS_ERROR(data->state.negotiate.status)) {
492
 
      auth="GSS-Negotiate";
493
 
      result = Curl_output_negotiate(conn, TRUE);
494
 
      if(result)
495
 
        return result;
496
 
      authproxy->done = TRUE;
497
 
    }
498
 
    else
499
 
#endif
500
 
#ifdef USE_NTLM
501
 
    if(authproxy->picked == CURLAUTH_NTLM) {
502
 
      auth="NTLM";
503
 
      result = Curl_output_ntlm(conn, TRUE);
504
 
      if(result)
505
 
        return result;
506
 
    }
507
 
    else
508
 
#endif
509
 
      if(authproxy->picked == CURLAUTH_BASIC) {
510
 
        /* Basic */
511
 
        if(conn->bits.proxy_user_passwd &&
512
 
           !checkheaders(data, "Proxy-authorization:")) {
513
 
          auth="Basic";
514
 
          result = http_output_basic(conn, TRUE);
515
 
          if(result)
516
 
            return result;
517
 
        }
518
 
        /* NOTE: http_output_basic() should set 'done' TRUE, as the other auth
519
 
           functions work that way */
520
 
        authproxy->done = TRUE;
521
 
      }
522
 
#ifndef CURL_DISABLE_CRYPTO_AUTH
523
 
      else if(authproxy->picked == CURLAUTH_DIGEST) {
524
 
        auth="Digest";
525
 
        result = Curl_output_digest(conn,
526
 
                                    TRUE, /* proxy */
527
 
                                    (const unsigned char *)request,
528
 
                                    (const unsigned char *)path);
529
 
        if(result)
530
 
          return result;
531
 
      }
532
 
#endif
533
 
      if(auth) {
534
 
        infof(data, "Proxy auth using %s with user '%s'\n",
535
 
              auth, conn->proxyuser?conn->proxyuser:"");
536
 
        authproxy->multi = (bool)(!authproxy->done);
537
 
      }
538
 
      else
539
 
        authproxy->multi = FALSE;
540
 
    }
 
647
    result = output_auth_headers(conn, authproxy, request, path, TRUE);
 
648
    if(result)
 
649
      return result;
 
650
  }
541
651
  else
 
652
#else
 
653
  (void)proxytunnel;
 
654
#endif /* CURL_DISABLE_PROXY */
542
655
    /* we have no proxy so let's pretend we're done authenticating
543
656
       with it */
544
657
    authproxy->done = TRUE;
548
661
  if(!data->state.this_is_a_follow ||
549
662
     conn->bits.netrc ||
550
663
     !data->state.first_host ||
551
 
     curl_strequal(data->state.first_host, conn->host.name) ||
552
 
     data->set.http_disable_hostname_check_before_authentication) {
553
 
 
554
 
    /* Send web authentication header if needed */
555
 
    {
556
 
      auth = NULL;
557
 
#ifdef HAVE_GSSAPI
558
 
      if((authhost->picked == CURLAUTH_GSSNEGOTIATE) &&
559
 
         data->state.negotiate.context &&
560
 
         !GSS_ERROR(data->state.negotiate.status)) {
561
 
        auth="GSS-Negotiate";
562
 
        result = Curl_output_negotiate(conn, FALSE);
563
 
        if(result)
564
 
          return result;
565
 
        authhost->done = TRUE;
566
 
      }
567
 
      else
568
 
#endif
569
 
#ifdef USE_NTLM
570
 
      if(authhost->picked == CURLAUTH_NTLM) {
571
 
        auth="NTLM";
572
 
        result = Curl_output_ntlm(conn, FALSE);
573
 
        if(result)
574
 
          return result;
575
 
      }
576
 
      else
577
 
#endif
578
 
      {
579
 
#ifndef CURL_DISABLE_CRYPTO_AUTH
580
 
        if(authhost->picked == CURLAUTH_DIGEST) {
581
 
          auth="Digest";
582
 
          result = Curl_output_digest(conn,
583
 
                                      FALSE, /* not a proxy */
584
 
                                      (const unsigned char *)request,
585
 
                                      (const unsigned char *)path);
586
 
          if(result)
587
 
            return result;
588
 
        } else
589
 
#endif
590
 
        if(authhost->picked == CURLAUTH_BASIC) {
591
 
          if(conn->bits.user_passwd &&
592
 
             !checkheaders(data, "Authorization:")) {
593
 
            auth="Basic";
594
 
            result = http_output_basic(conn, FALSE);
595
 
            if(result)
596
 
              return result;
597
 
          }
598
 
          /* basic is always ready */
599
 
          authhost->done = TRUE;
600
 
        }
601
 
      }
602
 
      if(auth) {
603
 
        infof(data, "Server auth using %s with user '%s'\n",
604
 
              auth, conn->user);
605
 
 
606
 
        authhost->multi = (bool)(!authhost->done);
607
 
      }
608
 
      else
609
 
        authhost->multi = FALSE;
610
 
    }
 
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);
611
667
  }
612
668
  else
613
669
    authhost->done = TRUE;
657
713
   * If the provided authentication is wanted as one out of several accepted
658
714
   * types (using &), we OR this authentication type to the authavail
659
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
   *
660
724
   */
661
725
 
662
726
#ifdef HAVE_GSSAPI
663
727
  if(checkprefix("GSS-Negotiate", start) ||
664
728
      checkprefix("Negotiate", start)) {
 
729
    int neg;
665
730
    *availp |= CURLAUTH_GSSNEGOTIATE;
666
731
    authp->avail |= CURLAUTH_GSSNEGOTIATE;
667
 
    if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
668
 
      /* if exactly this is wanted, go */
669
 
      int neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
 
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);
670
741
      if(neg == 0) {
 
742
        DEBUGASSERT(!data->req.newurl);
671
743
        data->req.newurl = strdup(data->change.url);
672
 
        data->state.authproblem = (data->req.newurl == NULL);
673
 
      }
674
 
      else {
675
 
        infof(data, "Authentication problem. Ignoring this.\n");
676
 
        data->state.authproblem = TRUE;
 
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;
677
749
      }
678
750
    }
679
751
  }
727
799
        authp->avail |= CURLAUTH_BASIC;
728
800
        if(authp->picked == CURLAUTH_BASIC) {
729
801
          /* We asked for Basic authentication but got a 40X back
730
 
             anyway, which basicly means our name+password isn't
 
802
             anyway, which basically means our name+password isn't
731
803
             valid. */
732
804
          authp->avail = CURLAUTH_NONE;
733
805
          infof(data, "Authentication problem. Ignoring this.\n");
906
978
static
907
979
send_buffer *add_buffer_init(void)
908
980
{
909
 
  send_buffer *blonk;
910
 
  blonk=(send_buffer *)malloc(sizeof(send_buffer));
911
 
  if(blonk) {
912
 
    memset(blonk, 0, sizeof(send_buffer));
913
 
    return blonk;
914
 
  }
915
 
  return NULL; /* failed, go home */
 
981
  return calloc(sizeof(send_buffer), 1);
916
982
}
917
983
 
918
984
/*
1126
1192
 
1127
1193
    if(in->buffer)
1128
1194
      /* we have a buffer, enlarge the existing one */
1129
 
      new_rb = (char *)realloc(in->buffer, new_size);
 
1195
      new_rb = realloc(in->buffer, new_size);
1130
1196
    else
1131
1197
      /* create a new buffer */
1132
 
      new_rb = (char *)malloc(new_size);
 
1198
      new_rb = malloc(new_size);
1133
1199
 
1134
1200
    if(!new_rb) {
1135
1201
      /* If we failed, we cleanup the whole buffer and return error */
1173
1239
  const char *start;
1174
1240
  const char *end;
1175
1241
 
1176
 
  if(!strnequal(headerline, header, hlen))
 
1242
  if(!Curl_raw_nequal(headerline, header, hlen))
1177
1243
    return FALSE; /* doesn't start with header */
1178
1244
 
1179
1245
  /* pass the header */
1199
1265
 
1200
1266
  /* find the content string in the rest of the line */
1201
1267
  for(;len>=clen;len--, start++) {
1202
 
    if(strnequal(start, content, clen))
 
1268
    if(Curl_raw_nequal(start, content, clen))
1203
1269
      return TRUE; /* match! */
1204
1270
  }
1205
1271
 
1206
1272
  return FALSE; /* no match */
1207
1273
}
1208
1274
 
 
1275
#ifndef CURL_DISABLE_PROXY
1209
1276
/*
1210
1277
 * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
1211
1278
 * function will issue the necessary commands to get a seamless tunnel through
1273
1340
      }
1274
1341
 
1275
1342
      /* Setup the proxy-authorization header, if any */
1276
 
      result = http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
 
1343
      result = http_output_auth(conn, "CONNECT", host_port, TRUE);
1277
1344
 
1278
1345
      if(CURLE_OK == result) {
1279
1346
        char *host=(char *)"";
1280
1347
        const char *proxyconn="";
1281
1348
        const char *useragent="";
 
1349
        const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
 
1350
          "1.0" : "1.1";
1282
1351
 
1283
1352
        if(!checkheaders(data, "Host:")) {
1284
1353
          host = aprintf("Host: %s\r\n", host_port);
1299
1368
        /* BLOCKING */
1300
1369
        result =
1301
1370
          add_bufferf(req_buffer,
1302
 
                      "CONNECT %s:%d HTTP/1.0\r\n"
 
1371
                      "CONNECT %s:%d HTTP/%s\r\n"
1303
1372
                      "%s"  /* Host: */
1304
1373
                      "%s"  /* Proxy-Authorization */
1305
1374
                      "%s"  /* User-Agent */
1306
1375
                      "%s", /* Proxy-Connection */
1307
 
                      hostname, remote_port,
 
1376
                      hostname, remote_port, http,
1308
1377
                      host,
1309
1378
                      conn->allocptr.proxyuserpwd?
1310
1379
                      conn->allocptr.proxyuserpwd:"",
1410
1479
        case 0: /* timeout */
1411
1480
          break;
1412
1481
        default:
 
1482
          DEBUGASSERT(ptr+BUFSIZE-nread <= data->state.buffer+BUFSIZE+1);
1413
1483
          res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
1414
1484
          if(res< 0)
1415
1485
            /* EWOULDBLOCK */
1442
1512
              /* This means we are currently ignoring a response-body */
1443
1513
 
1444
1514
              nread = 0; /* make next read start over in the read buffer */
 
1515
              ptr=data->state.buffer;
1445
1516
              if(cl) {
1446
1517
                /* A Content-Length based body: simply count down the counter
1447
1518
                   and make sure to break out of the loop when we're done! */
1501
1572
                    /* end of response-headers from the proxy */
1502
1573
                    nread = 0; /* make next read start over in the read
1503
1574
                                  buffer */
 
1575
                    ptr=data->state.buffer;
1504
1576
                    if((407 == k->httpcode) && !data->state.authproblem) {
1505
1577
                      /* If we get a 407 response code with content length
1506
1578
                         when we have no auth problem, we must ignore the
1659
1731
  data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
1660
1732
  return CURLE_OK;
1661
1733
}
 
1734
#endif /* CURL_DISABLE_PROXY */
1662
1735
 
1663
1736
/*
1664
1737
 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1675
1748
     function to make the re-use checks properly be able to check this bit. */
1676
1749
  conn->bits.close = FALSE;
1677
1750
 
 
1751
#ifndef CURL_DISABLE_PROXY
1678
1752
  /* If we are not using a proxy and we want a secure connection, perform SSL
1679
1753
   * initialization & connection now.  If using a proxy with https, then we
1680
1754
   * must tell the proxy to CONNECT to the host we want to talk to.  Only
1681
1755
   * after the connect has occurred, can we start talking SSL
1682
1756
   */
1683
 
 
1684
1757
  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1685
1758
 
1686
1759
    /* either SSL over proxy, or explicitly asked for */
1695
1768
    /* nothing else to do except wait right now - we're not done here. */
1696
1769
    return CURLE_OK;
1697
1770
  }
 
1771
#endif /* CURL_DISABLE_PROXY */
1698
1772
 
1699
1773
  if(!data->state.this_is_a_follow) {
1700
1774
    /* this is not a followed location, get the original host name */
1742
1816
  return GETSOCK_WRITESOCK(0);
1743
1817
}
1744
1818
 
 
1819
#ifdef USE_SSL
1745
1820
static CURLcode https_connecting(struct connectdata *conn, bool *done)
1746
1821
{
1747
1822
  CURLcode result;
1750
1825
  /* perform SSL initialization for this socket */
1751
1826
  result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
1752
1827
  if(result)
1753
 
    return result;
1754
 
 
1755
 
  return CURLE_OK;
 
1828
    conn->bits.close = TRUE; /* a failed connection is marked for closure
 
1829
                                to prevent (bad) re-use or similar */
 
1830
  return result;
1756
1831
}
 
1832
#endif
1757
1833
 
1758
1834
#ifdef USE_SSLEAY
1759
1835
/* This function is OpenSSL-specific. It should be made to query the generic
1880
1956
  return CURLE_OK;
1881
1957
}
1882
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. */
 
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
 
1883
1974
/* check and possibly add an Expect: header */
1884
1975
static CURLcode expect100(struct SessionHandle *data,
 
1976
                          struct connectdata *conn,
1885
1977
                          send_buffer *req_buffer)
1886
1978
{
1887
1979
  CURLcode result = CURLE_OK;
1888
1980
  data->state.expect100header = FALSE; /* default to false unless it is set
1889
1981
                                          to TRUE below */
1890
 
  if((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
1891
 
     !checkheaders(data, "Expect:")) {
 
1982
  if(use_http_1_1(data, conn) && !checkheaders(data, "Expect:")) {
1892
1983
    /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
1893
1984
       100-continue to the headers which actually speeds up post
1894
1985
       operations (as there is one packet coming back from the web
1922
2013
        if(conn->allocptr.host &&
1923
2014
           /* a Host: header was sent already, don't pass on any custom Host:
1924
2015
              header as that will produce *two* in the same request! */
1925
 
           curl_strnequal("Host:", headers->data, 5))
 
2016
           checkprefix("Host:", headers->data))
1926
2017
          ;
1927
2018
        else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
1928
2019
                /* this header (extended by formdata.c) is sent later */
1929
 
                curl_strnequal("Content-Type:", headers->data,
1930
 
                               strlen("Content-Type:")))
 
2020
                checkprefix("Content-Type:", headers->data))
1931
2021
          ;
1932
2022
        else {
1933
2023
          CURLcode result = add_bufferf(req_buffer, "%s\r\n", headers->data);
1952
2042
  char *buf = data->state.buffer; /* this is a short cut to the buffer */
1953
2043
  CURLcode result=CURLE_OK;
1954
2044
  struct HTTP *http;
1955
 
  char *ppath = data->state.path;
 
2045
  const char *ppath = data->state.path;
1956
2046
  char ftp_typecode[sizeof(";type=?")] = "";
1957
 
  char *host = conn->host.name;
 
2047
  const char *host = conn->host.name;
1958
2048
  const char *te = ""; /* transfer-encoding */
1959
 
  char *ptr;
1960
 
  char *request;
 
2049
  const char *ptr;
 
2050
  const char *request;
1961
2051
  Curl_HttpReq httpreq = data->set.httpreq;
1962
2052
  char *addcookies = NULL;
1963
2053
  curl_off_t included_body = 0;
1978
2068
  if(!data->state.proto.http) {
1979
2069
    /* Only allocate this struct if we don't already have it! */
1980
2070
 
1981
 
    http = (struct HTTP *)calloc(sizeof(struct HTTP), 1);
 
2071
    http = calloc(sizeof(struct HTTP), 1);
1982
2072
    if(!http)
1983
2073
      return CURLE_OUT_OF_MEMORY;
1984
2074
    data->state.proto.http = http;
1996
2086
    request = data->set.str[STRING_CUSTOMREQUEST];
1997
2087
  else {
1998
2088
    if(data->set.opt_no_body)
1999
 
      request = (char *)"HEAD";
 
2089
      request = "HEAD";
2000
2090
    else {
2001
2091
      DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
2002
2092
      switch(httpreq) {
2003
2093
      case HTTPREQ_POST:
2004
2094
      case HTTPREQ_POST_FORM:
2005
 
        request = (char *)"POST";
 
2095
        request = "POST";
2006
2096
        break;
2007
2097
      case HTTPREQ_PUT:
2008
 
        request = (char *)"PUT";
 
2098
        request = "PUT";
2009
2099
        break;
2010
2100
      default: /* this should never happen */
2011
2101
      case HTTPREQ_GET:
2012
 
        request = (char *)"GET";
 
2102
        request = "GET";
2013
2103
        break;
2014
2104
      case HTTPREQ_HEAD:
2015
 
        request = (char *)"HEAD";
 
2105
        request = "HEAD";
2016
2106
        break;
2017
2107
      }
2018
2108
    }
2069
2159
  else {
2070
2160
    if((conn->protocol&PROT_HTTP) &&
2071
2161
        data->set.upload &&
2072
 
        (data->set.infilesize == -1) &&
2073
 
        (data->set.httpversion != CURL_HTTP_VERSION_1_0)) {
2074
 
      /* HTTP, upload, unknown file size and not HTTP 1.0 */
2075
 
      data->req.upload_chunky = TRUE;
 
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
      }
2076
2170
    }
2077
2171
    else {
2078
2172
      /* else, no chunky upload */
2087
2181
 
2088
2182
  ptr = checkheaders(data, "Host:");
2089
2183
  if(ptr && (!data->state.this_is_a_follow ||
2090
 
             curl_strequal(data->state.first_host, conn->host.name))) {
 
2184
             Curl_raw_equal(data->state.first_host, conn->host.name))) {
2091
2185
#if !defined(CURL_DISABLE_COOKIES)
2092
2186
    /* If we have a given custom Host: header, we extract the host name in
2093
2187
       order to possibly use it for cookie reasons later on. We only allow the
2094
2188
       custom Host: header if this is NOT a redirect, as setting Host: in the
2095
2189
       redirected request is being out on thin ice. Except if the host name
2096
2190
       is the same as the first one! */
2097
 
    char *start = ptr+strlen("Host:");
2098
 
    while(*start && ISSPACE(*start ))
2099
 
      start++;
2100
 
    ptr = start; /* start host-scanning here */
2101
 
 
2102
 
    /* scan through the string to find the end (space or colon) */
2103
 
    while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr))
2104
 
      ptr++;
2105
 
 
2106
 
    if(ptr != start) {
2107
 
      size_t len=ptr-start;
 
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 */
2108
2201
      Curl_safefree(conn->allocptr.cookiehost);
2109
 
      conn->allocptr.cookiehost = malloc(len+1);
2110
 
      if(!conn->allocptr.cookiehost)
2111
 
        return CURLE_OUT_OF_MEMORY;
2112
 
      memcpy(conn->allocptr.cookiehost, start, len);
2113
 
      conn->allocptr.cookiehost[len]=0;
 
2202
      conn->allocptr.cookiehost = cookiehost;
2114
2203
    }
2115
2204
#endif
2116
2205
 
2140
2229
      return CURLE_OUT_OF_MEMORY;
2141
2230
  }
2142
2231
 
 
2232
#ifndef CURL_DISABLE_PROXY
2143
2233
  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy)  {
2144
2234
    /* Using a proxy but does not tunnel through it */
2145
2235
 
2186
2276
      if(checkprefix("ftp://", ppath) || checkprefix("ftps://", ppath)) {
2187
2277
        char *p = strstr(ppath, ";type=");
2188
2278
        if(p && p[6] && p[7] == 0) {
2189
 
          switch (toupper((int)((unsigned char)p[6]))) {
 
2279
          switch (Curl_raw_toupper(p[6])) {
2190
2280
          case 'A':
2191
2281
          case 'D':
2192
2282
          case 'I':
2201
2291
      }
2202
2292
    }
2203
2293
  }
 
2294
#endif /* CURL_DISABLE_PROXY */
 
2295
 
2204
2296
  if(HTTPREQ_POST_FORM == httpreq) {
2205
2297
    /* we must build the whole darned post sequence first, so that we have
2206
2298
       a size of the whole shebang before we start to send it */
2215
2307
  }
2216
2308
 
2217
2309
 
2218
 
  http->p_pragma =
2219
 
    (!checkheaders(data, "Pragma:") &&
2220
 
     (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )?
2221
 
    "Pragma: no-cache\r\n":NULL;
2222
 
 
2223
2310
  http->p_accept = checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
2224
2311
 
2225
2312
  if(( (HTTPREQ_POST == httpreq) ||
2298
2385
     * or uploading and we always let customized headers override our internal
2299
2386
     * ones if any such are specified.
2300
2387
     */
2301
 
    if((httpreq == HTTPREQ_GET) &&
 
2388
    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2302
2389
       !checkheaders(data, "Range:")) {
2303
2390
      /* if a line like this was already allocated, free the previous one */
2304
2391
      if(conn->allocptr.rangeline)
2313
2400
      if(conn->allocptr.rangeline)
2314
2401
        free(conn->allocptr.rangeline);
2315
2402
 
2316
 
      if(data->state.resume_from) {
 
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) {
2317
2414
        /* This is because "resume" was selected */
2318
2415
        curl_off_t total_expected_size=
2319
2416
          data->state.resume_from + data->set.infilesize;
2335
2432
    }
2336
2433
  }
2337
2434
 
2338
 
  /* Use 1.1 unless the use specificly asked for 1.0 */
2339
 
  httpstring= data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
 
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";
2340
2438
 
2341
2439
  /* initialize a dynamic send-buffer */
2342
2440
  req_buffer = add_buffer_init();
2354
2452
                "%s" /* range */
2355
2453
                "%s" /* user agent */
2356
2454
                "%s" /* host */
2357
 
                "%s" /* pragma */
2358
2455
                "%s" /* accept */
2359
2456
                "%s" /* accept-encoding */
2360
2457
                "%s" /* referer */
2374
2471
                 *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)?
2375
2472
                conn->allocptr.uagent:"",
2376
2473
                (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
2377
 
                http->p_pragma?http->p_pragma:"",
2378
2474
                http->p_accept?http->p_accept:"",
2379
2475
                (data->set.str[STRING_ENCODING] &&
2380
2476
                 *data->set.str[STRING_ENCODING] &&
2560
2656
        return result;
2561
2657
    }
2562
2658
 
2563
 
    result = expect100(data, req_buffer);
 
2659
    result = expect100(data, conn, req_buffer);
2564
2660
    if(result)
2565
2661
      return result;
2566
2662
 
2632
2728
        return result;
2633
2729
    }
2634
2730
 
2635
 
    result = expect100(data, req_buffer);
 
2731
    result = expect100(data, conn, req_buffer);
2636
2732
    if(result)
2637
2733
      return result;
2638
2734
 
2663
2759
 
2664
2760
    if(conn->bits.authneg)
2665
2761
      postsize = 0;
2666
 
    else
 
2762
    else {
2667
2763
      /* figure out the size of the postfields */
2668
2764
      postsize = (data->set.postfieldsize != -1)?
2669
2765
        data->set.postfieldsize:
2670
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;
2671
2817
 
2672
2818
        if(!data->req.upload_chunky) {
2673
 
          /* We only set Content-Length and allow a custom Content-Length if
2674
 
             we don't upload data chunked, as RFC2616 forbids us to set both
2675
 
             kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2676
 
 
2677
 
          if(!checkheaders(data, "Content-Length:")) {
2678
 
            /* we allow replacing this header, although it isn't very wise to
2679
 
               actually set your own */
2680
 
            result = add_bufferf(req_buffer,
2681
 
                                 "Content-Length: %" FORMAT_OFF_T"\r\n",
2682
 
                                 postsize);
2683
 
            if(result)
2684
 
              return result;
2685
 
          }
2686
 
        }
2687
 
 
2688
 
        if(!checkheaders(data, "Content-Type:")) {
2689
 
          result = add_bufferf(req_buffer,
2690
 
                               "Content-Type: application/x-www-form-urlencoded\r\n");
2691
 
          if(result)
2692
 
            return result;
2693
 
        }
2694
 
 
2695
 
        /* For really small posts we don't use Expect: headers at all, and for
2696
 
           the somewhat bigger ones we allow the app to disable it. Just make
2697
 
           sure that the expect100header is always set to the preferred value
2698
 
           here. */
2699
 
        if(postsize > TINY_INITIAL_POST_SIZE) {
2700
 
          result = expect100(data, req_buffer);
2701
 
          if(result)
2702
 
            return result;
2703
 
        }
2704
 
        else
2705
 
          data->state.expect100header = FALSE;
2706
 
 
2707
 
        if(data->set.postfields) {
2708
 
 
2709
 
          if(!data->state.expect100header &&
2710
 
             (postsize < MAX_INITIAL_POST_SIZE))  {
2711
 
            /* if we don't use expect: 100  AND
2712
 
               postsize is less than MAX_INITIAL_POST_SIZE
2713
 
 
2714
 
               then append the post data to the HTTP request header. This limit
2715
 
               is no magic limit but only set to prevent really huge POSTs to
2716
 
               get the data duplicated with malloc() and family. */
2717
 
 
2718
 
            result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2719
 
            if(result)
2720
 
              return result;
2721
 
 
2722
 
            if(!data->req.upload_chunky) {
2723
 
              /* We're not sending it 'chunked', append it to the request
2724
 
                 already now to reduce the number if send() calls */
2725
 
              result = add_buffer(req_buffer, data->set.postfields,
2726
 
                                  (size_t)postsize);
2727
 
              included_body = postsize;
2728
 
            }
2729
 
            else {
2730
 
              /* Append the POST data chunky-style */
2731
 
              result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
2732
 
              if(CURLE_OK == result)
2733
 
                result = add_buffer(req_buffer, data->set.postfields,
2734
 
                                    (size_t)postsize);
2735
 
              if(CURLE_OK == result)
2736
 
                result = add_buffer(req_buffer,
2737
 
                                    "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
2738
 
              /* CR  LF   0  CR  LF  CR  LF */
2739
 
              included_body = postsize + 7;
2740
 
            }
2741
 
            if(result)
2742
 
              return result;
2743
 
          }
2744
 
          else {
2745
 
            /* A huge POST coming up, do data separate from the request */
2746
 
            http->postsize = postsize;
2747
 
            http->postdata = data->set.postfields;
2748
 
 
2749
 
            http->sending = HTTPSEND_BODY;
2750
 
 
2751
 
            conn->fread_func = (curl_read_callback)readmoredata;
2752
 
            conn->fread_in = (void *)conn;
2753
 
 
2754
 
            /* set the upload size to the progress meter */
2755
 
            Curl_pgrsSetUploadSize(data, http->postsize);
2756
 
 
2757
 
            result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2758
 
            if(result)
2759
 
              return result;
2760
 
          }
 
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;
2761
2824
        }
2762
2825
        else {
2763
 
          result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
2764
 
          if(result)
2765
 
            return result;
2766
 
 
2767
 
          if(data->set.postfieldsize) {
2768
 
            /* set the upload size to the progress meter */
2769
 
            Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
2770
 
 
2771
 
            /* set the pointer to mark that we will send the post body using the
2772
 
               read callback, but only if we're not in authenticate
2773
 
               negotiation  */
2774
 
            if(!conn->bits.authneg) {
2775
 
              http->postdata = (char *)&http->postdata;
2776
 
              http->postsize = postsize;
2777
 
            }
2778
 
          }
2779
 
        }
2780
 
        /* issue the request */
2781
 
        result = add_buffer_send(req_buffer, conn, &data->info.request_size,
2782
 
                                 (size_t)included_body, FIRSTSOCKET);
2783
 
 
2784
 
        if(result)
2785
 
          failf(data, "Failed sending HTTP POST request");
2786
 
        else
2787
 
          result =
2788
 
            Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
2789
 
                                &http->readbytecount,
2790
 
                                http->postdata?FIRSTSOCKET:-1,
2791
 
                                http->postdata?&http->writebytecount:NULL);
2792
 
        break;
 
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;
2793
2889
 
2794
2890
  default:
2795
2891
    result = add_buffer(req_buffer, "\r\n", 2);