~ubuntu-branches/ubuntu/oneiric/curl/oneiric

« back to all changes in this revision

Viewing changes to lib/url.c

  • Committer: Bazaar Package Importer
  • Author(s): Artur Rona
  • Date: 2011-01-26 02:50:18 UTC
  • mfrom: (3.4.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110126025018-dzgm2m2t5d1vc9y4
Tags: 7.21.3-1ubuntu1
* Merge from debian unstable.  Remaining changes: (LP: #707756)
  - debian/control:
    + Build-Depends: Replace libssh2-1-dev with openssh-server.
      Drop stunnel since it's in universe, as well.
    + Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.
    Above changes are necessary to be independent from the universe.

Show diffs side-by-side

added added

removed removed

Lines of Context:
651
651
       close handles not in use.
652
652
    */
653
653
    for(i=newamount; i< c->num; i++)
654
 
      Curl_disconnect(c->connects[i]);
 
654
      Curl_disconnect(c->connects[i], /* dead_connection */ FALSE);
655
655
 
656
656
    /* If the most recent connection is no longer valid, mark it
657
657
       invalid. */
1006
1006
     * An FTP option that modifies an upload to create missing directories on
1007
1007
     * the server.
1008
1008
     */
1009
 
    data->set.ftp_create_missing_dirs = (int)va_arg(param, long);
 
1009
    switch(va_arg(param, long)) {
 
1010
    case 0:
 
1011
      data->set.ftp_create_missing_dirs = 0;
 
1012
      break;
 
1013
    case 1:
 
1014
      data->set.ftp_create_missing_dirs = 1;
 
1015
      break;
 
1016
    case 2:
 
1017
      data->set.ftp_create_missing_dirs = 2;
 
1018
      break;
 
1019
    default:
 
1020
      /* reserve other values for future use */
 
1021
      result = CURLE_FAILED_INIT;
 
1022
      break;
 
1023
    }
1010
1024
    break;
1011
1025
  case CURLOPT_SERVER_RESPONSE_TIMEOUT:
1012
1026
    /*
1750
1764
     */
1751
1765
    data->set.quote = va_arg(param, struct curl_slist *);
1752
1766
    break;
 
1767
  case CURLOPT_RESOLVE:
 
1768
    /*
 
1769
     * List of NAME:[address] names to populate the DNS cache with
 
1770
     * Prefix the NAME with dash (-) to _remove_ the name from the cache.
 
1771
     *
 
1772
     * Names added with this API will remain in the cache until explicitly
 
1773
     * removed or the handle is cleaned up.
 
1774
     *
 
1775
     * This API can remove any name from the DNS cache, but only entries
 
1776
     * that aren't actually in use right now will be pruned immediately.
 
1777
     */
 
1778
    data->set.resolve = va_arg(param, struct curl_slist *);
 
1779
    data->change.resolve = data->set.resolve;
 
1780
    break;
1753
1781
  case CURLOPT_PROGRESSFUNCTION:
1754
1782
    /*
1755
1783
     * Progress callback function
1987
2015
    /*
1988
2016
     * Set what local port to bind the socket to when performing an operation.
1989
2017
     */
1990
 
    data->set.localport = (unsigned short) va_arg(param, long);
 
2018
    data->set.localport = curlx_sltous(va_arg(param, long));
1991
2019
    break;
1992
2020
  case CURLOPT_LOCALPORTRANGE:
1993
2021
    /*
1994
2022
     * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
1995
2023
     */
1996
 
    data->set.localportrange = (int) va_arg(param, long);
 
2024
    data->set.localportrange = curlx_sltosi(va_arg(param, long));
1997
2025
    break;
1998
2026
  case CURLOPT_KRBLEVEL:
1999
2027
    /*
2166
2194
    data->set.max_filesize = va_arg(param, long);
2167
2195
    break;
2168
2196
 
 
2197
#ifdef USE_SSL
2169
2198
  case CURLOPT_USE_SSL:
2170
2199
    /*
2171
2200
     * Make transfers attempt to use SSL/TLS.
2172
2201
     */
2173
2202
    data->set.ftp_ssl = (curl_usessl)va_arg(param, long);
2174
2203
    break;
2175
 
 
 
2204
#endif
2176
2205
  case CURLOPT_FTPSSLAUTH:
2177
2206
    /*
2178
2207
     * Set a specific auth for FTP-SSL transfers.
2181
2210
    break;
2182
2211
 
2183
2212
  case CURLOPT_IPRESOLVE:
2184
 
    data->set.ip_version = va_arg(param, long);
 
2213
    data->set.ipver = va_arg(param, long);
2185
2214
    break;
2186
2215
 
2187
2216
  case CURLOPT_MAXFILESIZE_LARGE:
2341
2370
     * know that an unsigned int will always hold the value so we blindly
2342
2371
     * typecast to this type
2343
2372
     */
2344
 
    data->set.scope = (unsigned int) va_arg(param, long);
 
2373
    data->set.scope = curlx_sltoui(va_arg(param, long));
2345
2374
    break;
2346
2375
 
2347
2376
  case CURLOPT_PROTOCOLS:
2558
2587
  free(conn); /* free all the connection oriented data */
2559
2588
}
2560
2589
 
2561
 
CURLcode Curl_disconnect(struct connectdata *conn)
 
2590
CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
2562
2591
{
2563
2592
  struct SessionHandle *data;
2564
2593
  if(!conn)
2618
2647
 
2619
2648
  if(conn->handler->disconnect)
2620
2649
    /* This is set if protocol-specific cleanups should be made */
2621
 
    conn->handler->disconnect(conn);
 
2650
    conn->handler->disconnect(conn, dead_connection);
2622
2651
 
2623
2652
  if(-1 != conn->connectindex) {
2624
2653
    /* unlink ourselves! */
2709
2738
}
2710
2739
#endif /* CURL_DISABLE_RTSP */
2711
2740
 
2712
 
static bool IsPipeliningPossible(const struct SessionHandle *handle)
 
2741
static bool IsPipeliningPossible(const struct SessionHandle *handle,
 
2742
                                 const struct connectdata *conn)
2713
2743
{
2714
 
  if(handle->multi && Curl_multi_canPipeline(handle->multi) &&
2715
 
      (handle->set.httpreq == HTTPREQ_GET ||
2716
 
       handle->set.httpreq == HTTPREQ_HEAD) &&
2717
 
      handle->set.httpversion != CURL_HTTP_VERSION_1_0)
 
2744
  if((conn->handler->protocol & PROT_HTTP) &&
 
2745
     handle->multi && Curl_multi_canPipeline(handle->multi) &&
 
2746
     (handle->set.httpreq == HTTPREQ_GET ||
 
2747
      handle->set.httpreq == HTTPREQ_HEAD) &&
 
2748
     handle->set.httpversion != CURL_HTTP_VERSION_1_0)
2718
2749
    return TRUE;
2719
2750
 
2720
2751
  return FALSE;
2731
2762
CURLcode Curl_addHandleToPipeline(struct SessionHandle *data,
2732
2763
                                  struct curl_llist *pipeline)
2733
2764
{
2734
 
#ifdef DEBUGBUILD
2735
 
  if(!IsPipeliningPossible(data)) {
2736
 
    /* when not pipelined, there MUST be no handle in the list already */
2737
 
    if(pipeline->head)
2738
 
      infof(data, "PIPE when no PIPE supposed!\n");
2739
 
  }
2740
 
#endif
2741
2765
  if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
2742
2766
    return CURLE_OUT_OF_MEMORY;
2743
2767
  return CURLE_OK;
2847
2871
{
2848
2872
  long i;
2849
2873
  struct connectdata *check;
2850
 
  bool canPipeline = IsPipeliningPossible(data);
 
2874
  bool canPipeline = IsPipeliningPossible(data, needle);
2851
2875
 
2852
2876
  for(i=0; i< data->state.connc->num; i++) {
2853
2877
    bool match = FALSE;
2886
2910
        check->data = data;
2887
2911
        infof(data, "Connection #%ld seems to be dead!\n", i);
2888
2912
 
2889
 
        Curl_disconnect(check); /* disconnect resources */
 
2913
        /* disconnect resources */
 
2914
        Curl_disconnect(check, /* dead_connection */ TRUE);
2890
2915
        data->state.connc->connects[i]=NULL; /* nothing here */
2891
2916
 
2892
2917
        continue;
2898
2923
      struct SessionHandle* sh = gethandleathead(check->send_pipe);
2899
2924
      struct SessionHandle* rh = gethandleathead(check->recv_pipe);
2900
2925
      if(sh) {
2901
 
        if(!IsPipeliningPossible(sh))
 
2926
        if(!IsPipeliningPossible(sh, check))
2902
2927
          continue;
2903
2928
      }
2904
2929
      else if(rh) {
2905
 
        if(!IsPipeliningPossible(rh))
 
2930
        if(!IsPipeliningPossible(rh, check))
2906
2931
          continue;
2907
2932
      }
2908
2933
 
3073
3098
    conn->data = data;
3074
3099
 
3075
3100
    /* the winner gets the honour of being disconnected */
3076
 
    (void)Curl_disconnect(conn);
 
3101
    (void)Curl_disconnect(conn, /* dead_connection */ FALSE);
3077
3102
 
3078
3103
    /* clean the array entry */
3079
3104
    data->state.connc->connects[connindex] = NULL;
3440
3465
#endif
3441
3466
}
3442
3467
 
 
3468
static void llist_dtor(void *user, void *element)
 
3469
{
 
3470
  (void)user;
 
3471
  (void)element;
 
3472
  /* Do nothing */
 
3473
}
 
3474
 
3443
3475
/*
3444
3476
 * Allocate and initialize a new connectdata object.
3445
3477
 */
3446
 
static struct connectdata *allocate_conn(void)
 
3478
static struct connectdata *allocate_conn(struct SessionHandle *data)
3447
3479
{
3448
 
  struct connectdata *conn;
3449
 
 
3450
 
  conn = calloc(1, sizeof(struct connectdata));
 
3480
  struct connectdata *conn = calloc(1, sizeof(struct connectdata));
3451
3481
  if(!conn)
3452
3482
    return NULL;
3453
3483
 
3470
3500
  /* Store creation time to help future close decision making */
3471
3501
  conn->created = Curl_tvnow();
3472
3502
 
 
3503
  conn->data = data; /* Setup the association between this connection
 
3504
                        and the SessionHandle */
 
3505
 
 
3506
  conn->proxytype = data->set.proxytype; /* type */
 
3507
 
 
3508
#ifdef CURL_DISABLE_PROXY
 
3509
 
 
3510
  conn->bits.proxy = FALSE;
 
3511
  conn->bits.httpproxy = FALSE;
 
3512
  conn->bits.proxy_user_passwd = FALSE;
 
3513
  conn->bits.tunnel_proxy = FALSE;
 
3514
 
 
3515
#else /* CURL_DISABLE_PROXY */
 
3516
 
 
3517
  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
 
3518
                            *data->set.str[STRING_PROXY]);
 
3519
  conn->bits.httpproxy = (bool)(conn->bits.proxy &&
 
3520
                                (conn->proxytype == CURLPROXY_HTTP ||
 
3521
                                 conn->proxytype == CURLPROXY_HTTP_1_0));
 
3522
  conn->bits.proxy_user_passwd =
 
3523
    (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]);
 
3524
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
 
3525
 
 
3526
#endif /* CURL_DISABLE_PROXY */
 
3527
 
 
3528
  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]);
 
3529
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
 
3530
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
 
3531
 
 
3532
  conn->verifypeer = data->set.ssl.verifypeer;
 
3533
  conn->verifyhost = data->set.ssl.verifyhost;
 
3534
 
 
3535
  conn->ip_version = data->set.ipver;
 
3536
 
 
3537
  if(data->multi && Curl_multi_canPipeline(data->multi) &&
 
3538
      !conn->master_buffer) {
 
3539
    /* Allocate master_buffer to be used for pipelining */
 
3540
    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
 
3541
    if(!conn->master_buffer)
 
3542
      goto error;
 
3543
  }
 
3544
 
 
3545
  /* Initialize the pipeline lists */
 
3546
  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
 
3547
  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
 
3548
  conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
 
3549
  conn->done_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
 
3550
  if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe ||
 
3551
     !conn->done_pipe)
 
3552
    goto error;
 
3553
 
 
3554
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
 
3555
  conn->data_prot = PROT_CLEAR;
 
3556
#endif
 
3557
 
3473
3558
  return conn;
 
3559
  error:
 
3560
  Curl_llist_destroy(conn->send_pipe, NULL);
 
3561
  Curl_llist_destroy(conn->recv_pipe, NULL);
 
3562
  Curl_llist_destroy(conn->pend_pipe, NULL);
 
3563
  Curl_llist_destroy(conn->done_pipe, NULL);
 
3564
  Curl_safefree(conn->master_buffer);
 
3565
  Curl_safefree(conn);
 
3566
  return NULL;
3474
3567
}
3475
3568
 
3476
3569
static CURLcode findprotocol(struct SessionHandle *data,
3596
3689
    path[0]=0;
3597
3690
 
3598
3691
    if(2 > sscanf(data->change.url,
3599
 
                   "%15[^\n:]://%[^\n/]%[^\n]",
 
3692
                   "%15[^\n:]://%[^\n/?]%[^\n]",
3600
3693
                   protobuf,
3601
3694
                   conn->host.name, path)) {
3602
3695
 
3604
3697
       * The URL was badly formatted, let's try the browser-style _without_
3605
3698
       * protocol specified like 'http://'.
3606
3699
       */
3607
 
      rc = sscanf(data->change.url, "%[^\n/]%[^\n]", conn->host.name, path);
 
3700
      rc = sscanf(data->change.url, "%[^\n/?]%[^\n]", conn->host.name, path);
3608
3701
      if(1 > rc) {
3609
3702
        /*
3610
3703
         * We couldn't even get this format.
3736
3829
  return findprotocol(data, conn, protop);
3737
3830
}
3738
3831
 
3739
 
static void llist_dtor(void *user, void *element)
3740
 
{
3741
 
  (void)user;
3742
 
  (void)element;
3743
 
  /* Do nothing */
3744
 
}
3745
 
 
3746
3832
/*
3747
3833
 * If we're doing a resumed transfer, we need to setup our stuff
3748
3834
 * properly.
4079
4165
    *prox_portno = 0x0; /* cut off number from host name */
4080
4166
    prox_portno ++;
4081
4167
    /* now set the local port number */
4082
 
    conn->port = atoi(prox_portno);
 
4168
    conn->port = strtol(prox_portno, NULL, 10);
4083
4169
  }
4084
4170
  else {
4085
4171
    /* without a port number after the host name, some people seem to use
4523
4609
  else
4524
4610
    free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
4525
4611
 
 
4612
  /* persist connection info in session handle */
 
4613
  Curl_persistconninfo(conn);
 
4614
 
4526
4615
  /* re-use init */
4527
4616
  conn->bits.reuse = TRUE; /* yes, we're re-using here */
4528
4617
 
4580
4669
     parts for checking against the already present connections. In order
4581
4670
     to not have to modify everything at once, we allocate a temporary
4582
4671
     connection data struct and fill in for comparison purposes. */
 
4672
  conn = allocate_conn(data);
4583
4673
 
4584
 
  conn = allocate_conn();
 
4674
  if(!conn)
 
4675
    return CURLE_OUT_OF_MEMORY;
4585
4676
 
4586
4677
  /* We must set the return variable as soon as possible, so that our
4587
4678
     parent can cleanup any possible allocs we may have done before
4588
4679
     any failure */
4589
4680
  *in_connect = conn;
4590
4681
 
4591
 
  if(!conn)
4592
 
    return CURLE_OUT_OF_MEMORY;
4593
 
 
4594
 
  conn->data = data; /* Setup the association between this connection
4595
 
                        and the SessionHandle */
4596
 
 
4597
 
  conn->proxytype = data->set.proxytype; /* type */
4598
 
 
4599
 
#ifdef CURL_DISABLE_PROXY
4600
 
 
4601
 
  conn->bits.proxy = FALSE;
4602
 
  conn->bits.httpproxy = FALSE;
4603
 
  conn->bits.proxy_user_passwd = FALSE;
4604
 
  conn->bits.tunnel_proxy = FALSE;
4605
 
 
4606
 
#else /* CURL_DISABLE_PROXY */
4607
 
 
4608
 
  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
4609
 
                            *data->set.str[STRING_PROXY]);
4610
 
  conn->bits.httpproxy = (bool)(conn->bits.proxy &&
4611
 
                                (conn->proxytype == CURLPROXY_HTTP ||
4612
 
                                 conn->proxytype == CURLPROXY_HTTP_1_0));
4613
 
  conn->bits.proxy_user_passwd =
4614
 
    (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]);
4615
 
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
4616
 
 
4617
 
#endif /* CURL_DISABLE_PROXY */
4618
 
 
4619
 
  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]);
4620
 
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
4621
 
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
4622
 
 
4623
 
  conn->verifypeer = data->set.ssl.verifypeer;
4624
 
  conn->verifyhost = data->set.ssl.verifyhost;
4625
 
 
4626
 
  if(data->multi && Curl_multi_canPipeline(data->multi) &&
4627
 
      !conn->master_buffer) {
4628
 
    /* Allocate master_buffer to be used for pipelining */
4629
 
    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
4630
 
    if(!conn->master_buffer)
4631
 
      return CURLE_OUT_OF_MEMORY;
4632
 
  }
4633
 
 
4634
 
  /* Initialize the pipeline lists */
4635
 
  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
4636
 
  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
4637
 
  conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
4638
 
  conn->done_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
4639
 
  if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe ||
4640
 
    !conn->done_pipe)
4641
 
    return CURLE_OUT_OF_MEMORY;
4642
 
 
4643
4682
  /* This initing continues below, see the comment "Continue connectdata
4644
4683
   * initialization here" */
4645
4684
 
4899
4938
    infof(data, "Re-using existing connection! (#%ld) with host %s\n",
4900
4939
          conn->connectindex,
4901
4940
          conn->proxy.name?conn->proxy.dispname:conn->host.dispname);
4902
 
    /* copy this IP address to the common buffer for the easy handle so that
4903
 
       the address can actually survice the removal of this connection. strcpy
4904
 
       is safe since the target buffer is big enough to hold the largest
4905
 
       possible IP address */
4906
 
    strcpy(data->info.ip, conn->ip_addr_str);
4907
 
 
4908
4941
  }
4909
4942
  else {
4910
4943
    /*
5079
5112
  if(code && *in_connect) {
5080
5113
    /* We're not allowed to return failure with memory left allocated
5081
5114
       in the connectdata struct, free those here */
5082
 
    Curl_disconnect(*in_connect); /* close the connection */
 
5115
    Curl_disconnect(*in_connect, FALSE); /* close the connection */
5083
5116
    *in_connect = NULL;           /* return a NULL */
5084
5117
  }
5085
5118
 
5107
5140
  if(code)
5108
5141
    /* We're not allowed to return failure with memory left allocated
5109
5142
       in the connectdata struct, free those here */
5110
 
    Curl_disconnect(conn); /* close the connection */
 
5143
    Curl_disconnect(conn, FALSE); /* close the connection */
5111
5144
 
5112
5145
  return code;
5113
5146
#else
5199
5232
  */
5200
5233
  if(data->set.reuse_forbid || conn->bits.close || premature ||
5201
5234
     (-1 == conn->connectindex)) {
5202
 
    CURLcode res2 = Curl_disconnect(conn); /* close the connection */
 
5235
    CURLcode res2 = Curl_disconnect(conn, FALSE); /* close the connection */
5203
5236
 
5204
5237
    /* If we had an error already, make sure we return that one. But
5205
5238
       if we got a new error, return that. */