Skip to content
http.c 72.9 KiB
Newer Older
              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;
      if(!checkheaders(data, "Content-Type:")) {
Daniel Stenberg's avatar
Daniel Stenberg committed
        /* Get Content-Type: line from Curl_formpostheader.

           The Content-Type header line also contains the MIME boundary
           string etc why disabling this header is likely to not make things
Daniel Stenberg's avatar
Daniel Stenberg committed
           work, but we support disabling it anyway.
        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
}