Skip to content
http.c 73 KiB
Newer Older
        /* now loop through all cookies that matched */
        while(co) {
          if(co->value) {
            if(0 == count) {
              result = add_bufferf(req_buffer, "Cookie: ");
              if(result)
                break;
            }
            result = add_bufferf(req_buffer,
                                 "%s%s=%s", count?"; ":"",
                                 co->name, co->value);
          co = co->next; /* next cookie please */
Daniel Stenberg's avatar
Daniel Stenberg committed
        }
        Curl_cookie_freelist(store); /* free the cookie list */
Daniel Stenberg's avatar
Daniel Stenberg committed
      }
      if(addcookies && (CURLE_OK == result)) {
        if(!count)
          result = add_bufferf(req_buffer, "Cookie: ");
        if(CURLE_OK == result) {
          result = add_bufferf(req_buffer, "%s%s",
                               count?"; ":"",
                               addcookies);
          count++;
        }
      }
      if(count && (CURLE_OK == result))
        result = add_buffer(req_buffer, "\r\n", 2);

Daniel Stenberg's avatar
Daniel Stenberg committed
    }
Daniel Stenberg's avatar
Daniel Stenberg committed

Daniel Stenberg's avatar
Daniel Stenberg committed

      /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
       * header family should have their times set in GMT as RFC2616 defines:
       * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
       * (GMT), without exception. For the purposes of HTTP, GMT is exactly
       * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
       */

Daniel Stenberg's avatar
Daniel Stenberg committed
#ifdef HAVE_GMTIME_R
Daniel Stenberg's avatar
Daniel Stenberg committed
      /* thread-safe version */
      struct tm keeptime;
      tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
Daniel Stenberg's avatar
Daniel Stenberg committed
#else
Daniel Stenberg's avatar
Daniel Stenberg committed
#endif
Daniel Stenberg's avatar
Daniel Stenberg committed

      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
      snprintf(buf, BUFSIZE-1,
               "%s, %02d %s %4d %02d:%02d:%02d GMT",
               Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
               tm->tm_mday,
               Curl_month[tm->tm_mon],
               tm->tm_year + 1900,
               tm->tm_hour,
               tm->tm_min,
               tm->tm_sec);

      case CURL_TIMECOND_IFMODSINCE:
Daniel Stenberg's avatar
Daniel Stenberg committed
      default:
        result = add_bufferf(req_buffer,
                             "If-Modified-Since: %s\r\n", buf);
Daniel Stenberg's avatar
Daniel Stenberg committed
        break;
      case CURL_TIMECOND_IFUNMODSINCE:
        result = add_bufferf(req_buffer,
                             "If-Unmodified-Since: %s\r\n", buf);
Daniel Stenberg's avatar
Daniel Stenberg committed
        break;
      case CURL_TIMECOND_LASTMOD:
        result = add_bufferf(req_buffer,
                             "Last-Modified: %s\r\n", buf);
Daniel Stenberg's avatar
Daniel Stenberg committed
        break;
      }
    result = add_custom_headers(conn, req_buffer);
    if(result)
      return result;
Daniel Stenberg's avatar
Daniel Stenberg committed

    http->postdata = NULL;  /* nothing to post at this point */
    Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
    /* If 'authdone' is FALSE, we must not set the write socket index to the
       Curl_transfer() call below, as we're not ready to actually upload any
       data yet. */
      if(!http->sendit || conn->bits.authneg) {
        /* nothing to post! */
        result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
        if(result)
          return result;

        result = add_buffer_send(req_buffer, conn,
                                 &data->info.request_size, FIRSTSOCKET);
        if(result)
          failf(data, "Failed sending POST request");
        else
          /* setup variables for the upcoming transfer */
          result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                                 &http->readbytecount,
                                 -1, NULL);
        break;
      }

      if(Curl_FormInit(&http->form, http->sendit)) {
        failf(data, "Internal HTTP POST error!");
        return CURLE_HTTP_POST_ERROR;
      /* set the read function to read from the generated form data */
      conn->fread = (curl_read_callback)Curl_FormReader;
      conn->fread_in = &http->form;
Daniel Stenberg's avatar
Daniel Stenberg committed

      if(!conn->bits.upload_chunky) {
        /* only add Content-Length if not uploading chunked */
        result = add_bufferf(req_buffer,
                             "Content-Length: %" FORMAT_OFF_T "\r\n",
                             http->postsize);
        if(result)
          return result;
      }
      result = expect100(data, req_buffer);
      if(result)
        return result;
        /* Get Content-Type: line from Curl_formpostheader.
        size_t linelength=0;
        contentType = Curl_formpostheader((void *)&http->form,
                                          &linelength);
        if(!contentType) {
          failf(data, "Could not get Content-Type header line!");
        result = add_buffer(req_buffer, contentType, linelength);
        if(result)
          return result;
      /* make the request end in a true CRLF */
      result = add_buffer(req_buffer, "\r\n", 2);
      if(result)
        return result;
      /* set upload size to the progress meter */
      Curl_pgrsSetUploadSize(data, http->postsize);
Daniel Stenberg's avatar
Daniel Stenberg committed

      /* fire away the whole request to the server */
      result = add_buffer_send(req_buffer, conn,
                               &data->info.request_size, FIRSTSOCKET);
      if(result)
        failf(data, "Failed sending POST request");
      else
        /* setup variables for the upcoming transfer */
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                               FIRSTSOCKET,
                               &http->writebytecount);
        Curl_formclean(http->sendit); /* free that whole lot */
Daniel Stenberg's avatar
Daniel Stenberg committed
      }
      break;

    case HTTPREQ_PUT: /* Let's PUT the data to the server! */
Daniel Stenberg's avatar
Daniel Stenberg committed

      if(conn->bits.authneg)
        postsize = 0;
      else
        postsize = data->set.infilesize;

      if((postsize != -1) && !conn->bits.upload_chunky) {
        /* only add Content-Length if not uploading chunked */
        result = add_bufferf(req_buffer,
                             "Content-Length: %" FORMAT_OFF_T "\r\n",
                             postsize );
      result = expect100(data, req_buffer);
      if(result)
        return result;
Daniel Stenberg's avatar
Daniel Stenberg committed

      result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
      if(result)
        return result;
      /* set the upload size to the progress meter */
      Curl_pgrsSetUploadSize(data, postsize);
Daniel Stenberg's avatar
Daniel Stenberg committed

      /* this sends the buffer and frees all the buffer resources */
      result = add_buffer_send(req_buffer, conn,
                               &data->info.request_size, FIRSTSOCKET);
        failf(data, "Failed sending PUT request");
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                               postsize?FIRSTSOCKET:-1,
                               postsize?&http->writebytecount:NULL);
Daniel Stenberg's avatar
Daniel Stenberg committed
      if(result)
        return result;
    case HTTPREQ_POST:
      /* this is the simple POST, using x-www-form-urlencoded style */
      if(conn->bits.authneg)
        postsize = 0;
      else
        /* figure out the size of the postfields */
        postsize = (data->set.postfieldsize != -1)?
          data->set.postfieldsize:
          (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
      if(!conn->bits.upload_chunky) {
        /* We only set Content-Length and allow a custom Content-Length if
           we don't upload data chunked, as RFC2616 forbids us to set both
           kinds of headers (Transfer-Encoding: chunked and Content-Length) */

        if(!checkheaders(data, "Content-Length:")) {
          /* we allow replacing this header, although it isn't very wise to
             actually set your own */
          result = add_bufferf(req_buffer,
                               "Content-Length: %" FORMAT_OFF_T"\r\n",
                               postsize);
          if(result)
            return result;
        }
      if(!checkheaders(data, "Content-Type:")) {
        result = add_bufferf(req_buffer,
                             "Content-Type: application/x-www-form-urlencoded\r\n");
        if(result)
          return result;
      }
        if((data->state.authhost.done || data->state.authproxy.done )
           && (postsize < MAX_INITIAL_POST_SIZE)) {
Daniel Stenberg's avatar
Daniel Stenberg committed
          /* If we're not done with the authentication phase, we don't expect
             to actually send off any data yet. Hence, we delay the sending of
             the body until we receive that friendly 100-continue response */
          /* The post data is less than MAX_INITIAL_PORT_SIZE, then append it
             to the header. This limit is no magic limit but only set to
             prevent really huge POSTs to get the data duplicated with
             malloc() and family. */
Daniel Stenberg's avatar
Daniel Stenberg committed
          result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
Daniel Stenberg's avatar
Daniel Stenberg committed

            /* We're not sending it 'chunked', append it to the request
               already now to reduce the number if send() calls */
            result = add_buffer(req_buffer, data->set.postfields,
                                (size_t)postsize);
          }
          else {
            /* Append the POST data chunky-style */
            result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
            if(CURLE_OK == result)
              result = add_buffer(req_buffer, data->set.postfields,
                                  (size_t)postsize);
            if(CURLE_OK == result)
              result = add_buffer(req_buffer,
                                  "\r\n0\r\n\r\n", 7); /* end of a chunked
                                                          transfer stream */
          /* A huge POST coming up, do data separate from the request */
          http->postsize = postsize;
          http->postdata = data->set.postfields;
          conn->fread = (curl_read_callback)readmoredata;
          conn->fread_in = (void *)conn;

          /* set the upload size to the progress meter */
          Curl_pgrsSetUploadSize(data, http->postsize);
Daniel Stenberg's avatar
Daniel Stenberg committed

          result = expect100(data, req_buffer);
          if(result)
            return result;
Daniel Stenberg's avatar
Daniel Stenberg committed

          add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
        result = expect100(data, req_buffer);
        if(result)
          return result;

Daniel Stenberg's avatar
Daniel Stenberg committed
        add_buffer(req_buffer, "\r\n", 2); /* end of headers! */

        if(data->set.postfieldsize) {
          /* set the upload size to the progress meter */
          Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
          /* set the pointer to mark that we will send the post body using
             the read callback */
          http->postdata = (char *)&http->postdata;
        }
      result = add_buffer_send(req_buffer, conn,
                               &data->info.request_size, FIRSTSOCKET);

      if(result)
        failf(data, "Failed sending HTTP POST request");
          Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                        http->postdata?&http->writebytecount:NULL);
    default:
      add_buffer(req_buffer, "\r\n", 2);
      /* issue the request */
      result = add_buffer_send(req_buffer, conn,
                               &data->info.request_size, FIRSTSOCKET);
      if(result)
        failf(data, "Failed sending HTTP request");
      else
        /* HTTP GET/HEAD download: */
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                               http->postdata?&http->writebytecount:NULL);
Daniel Stenberg's avatar
Daniel Stenberg committed
    if(result)
      return result;
Daniel Stenberg's avatar
Daniel Stenberg committed

  return CURLE_OK;
Daniel Stenberg's avatar
Daniel Stenberg committed
}