Newer
Older
Daniel Stenberg
committed
/* 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);
Daniel Stenberg
committed
break;
count++;
Daniel Stenberg
committed
co = co->next; /* next cookie please */
Daniel Stenberg
committed
Curl_cookie_freelist(store); /* free the cookie list */
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
committed
if(result)
return result;
#endif
Daniel Stenberg
committed
if(data->set.timecondition) {
struct tm *tm;
/* 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).
*/
/* thread-safe version */
struct tm keeptime;
tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
tm = gmtime(&data->set.timevalue);
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);
Daniel Stenberg
committed
switch(data->set.timecondition) {
case CURL_TIMECOND_IFMODSINCE:
result = add_bufferf(req_buffer,
"If-Modified-Since: %s\r\n", buf);
case CURL_TIMECOND_IFUNMODSINCE:
result = add_bufferf(req_buffer,
"If-Unmodified-Since: %s\r\n", buf);
case CURL_TIMECOND_LASTMOD:
result = add_bufferf(req_buffer,
"Last-Modified: %s\r\n", buf);
if(result)
return result;
result = add_custom_headers(conn, req_buffer);
if(result)
return result;
http->postdata = NULL; /* nothing to post at this point */
Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
Daniel Stenberg
committed
/* 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. */
Daniel Stenberg
committed
switch(httpreq) {
case HTTPREQ_POST_FORM:
if(!http->sendit || conn->bits.authneg) {
Daniel Stenberg
committed
/* 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,
Daniel Stenberg
committed
&data->info.request_size, FIRSTSOCKET);
Daniel Stenberg
committed
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
committed
http->sending = HTTPSEND_BODY;
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.
Daniel Stenberg
committed
char *contentType;
Daniel Stenberg
committed
contentType = Curl_formpostheader((void *)&http->form,
&linelength);
if(!contentType) {
failf(data, "Could not get Content-Type header line!");
return CURLE_HTTP_POST_ERROR;
}
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;
Daniel Stenberg
committed
/* set upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
/* fire away the whole request to the server */
result = add_buffer_send(req_buffer, conn,
Daniel Stenberg
committed
&data->info.request_size, FIRSTSOCKET);
Daniel Stenberg
committed
if(result)
failf(data, "Failed sending POST request");
else
/* setup variables for the upcoming transfer */
Daniel Stenberg
committed
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
Daniel Stenberg
committed
&http->readbytecount,
FIRSTSOCKET,
&http->writebytecount);
Curl_formclean(http->sendit); /* free that whole lot */
break;
case HTTPREQ_PUT: /* Let's PUT the data to the server! */
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 );
if(result)
return result;
}
result = expect100(data, req_buffer);
if(result)
return result;
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
if(result)
return result;
Daniel Stenberg
committed
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, postsize);
Daniel Stenberg
committed
/* this sends the buffer and frees all the buffer resources */
Daniel Stenberg
committed
result = add_buffer_send(req_buffer, conn,
Daniel Stenberg
committed
&data->info.request_size, FIRSTSOCKET);
Daniel Stenberg
committed
if(result)
failf(data, "Failed sending PUT request");
Daniel Stenberg
committed
else
/* prepare for transfer */
Daniel Stenberg
committed
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
Daniel Stenberg
committed
&http->readbytecount,
postsize?FIRSTSOCKET:-1,
postsize?&http->writebytecount:NULL);
break;
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->set.postfields) {
if((data->state.authhost.done || data->state.authproxy.done )
&& (postsize < MAX_INITIAL_POST_SIZE)) {
/* 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. */
result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
Daniel Stenberg
committed
if(result)
return result;
Daniel Stenberg
committed
if(!conn->bits.upload_chunky) {
/* We're not sending it 'chunked', append it to the request
already now to reduce the number if send() calls */
Daniel Stenberg
committed
result = add_buffer(req_buffer, data->set.postfields,
(size_t)postsize);
}
else {
/* Append the POST data chunky-style */
Daniel Stenberg
committed
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 */
}
Daniel Stenberg
committed
if(result)
return result;
Daniel Stenberg
committed
}
else {
/* A huge POST coming up, do data separate from the request */
Daniel Stenberg
committed
http->postsize = postsize;
http->postdata = data->set.postfields;
Daniel Stenberg
committed
Daniel Stenberg
committed
http->sending = HTTPSEND_BODY;
Daniel Stenberg
committed
Daniel Stenberg
committed
conn->fread = (curl_read_callback)readmoredata;
conn->fread_in = (void *)conn;
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
result = expect100(data, req_buffer);
if(result)
return result;
add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
Daniel Stenberg
committed
}
result = expect100(data, req_buffer);
if(result)
return result;
add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
Daniel Stenberg
committed
if(data->set.postfieldsize) {
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
Daniel Stenberg
committed
/* set the pointer to mark that we will send the post body using
the read callback */
http->postdata = (char *)&http->postdata;
}
}
/* issue the request */
Daniel Stenberg
committed
result = add_buffer_send(req_buffer, conn,
Daniel Stenberg
committed
&data->info.request_size, FIRSTSOCKET);
if(result)
failf(data, "Failed sending HTTP POST request");
result =
Daniel Stenberg
committed
Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
Daniel Stenberg
committed
&http->readbytecount,
Daniel Stenberg
committed
http->postdata?FIRSTSOCKET:-1,
Daniel Stenberg
committed
http->postdata?&http->writebytecount:NULL);
break;
default:
add_buffer(req_buffer, "\r\n", 2);
Daniel Stenberg
committed
result = add_buffer_send(req_buffer, conn,
Daniel Stenberg
committed
&data->info.request_size, FIRSTSOCKET);
Daniel Stenberg
committed
if(result)
failf(data, "Failed sending HTTP request");
else
/* HTTP GET/HEAD download: */
Daniel Stenberg
committed
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
Daniel Stenberg
committed
&http->readbytecount,
Daniel Stenberg
committed
http->postdata?FIRSTSOCKET:-1,
Daniel Stenberg
committed
http->postdata?&http->writebytecount:NULL);
Daniel Stenberg
committed
}