new
[libcurl.git] / lib / http.c
blob76d7fcfc85ed5b5f3cdb3c5ad84d830c5bb75f0d
1 /*****************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * The contents of this file are subject to the Mozilla Public License
9 * Version 1.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
15 * License for the specific language governing rights and limitations
16 * under the License.
18 * The Original Code is Curl.
20 * The Initial Developer of the Original Code is Daniel Stenberg.
22 * Portions created by the Initial Developer are Copyright (C) 1998.
23 * All Rights Reserved.
25 * ------------------------------------------------------------
26 * Main author:
27 * - Daniel Stenberg <Daniel.Stenberg@haxx.nu>
29 * http://curl.haxx.nu
31 * $Source: /cvsroot/curl/curl/lib/http.c,v $
32 * $Revision: 1.1.1.1 $
33 * $Date: 1999-12-29 14:21:31 $
34 * $Author: bagder $
35 * $State: Exp $
36 * $Locker: $
38 * ------------------------------------------------------------
39 ****************************************************************************/
41 /* -- WIN32 approved -- */
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include <stdlib.h>
46 #include <ctype.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
50 #include <errno.h>
52 #include "setup.h"
54 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
55 #include <winsock.h>
56 #include <time.h>
57 #include <io.h>
58 #else
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
61 #endif
62 #include <netinet/in.h>
63 #include <sys/time.h>
64 #include <sys/resource.h>
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68 #include <netdb.h>
69 #ifdef HAVE_ARPA_INET_H
70 #include <arpa/inet.h>
71 #endif
72 #ifdef HAVE_NET_IF_H
73 #include <net/if.h>
74 #endif
75 #include <sys/ioctl.h>
76 #include <signal.h>
78 #ifdef HAVE_SYS_PARAM_H
79 #include <sys/param.h>
80 #endif
82 #ifdef HAVE_SYS_SELECT_H
83 #include <sys/select.h>
84 #endif
87 #endif
89 #include "urldata.h"
90 #include <curl/curl.h>
91 #include "download.h"
92 #include "sendf.h"
93 #include "formdata.h"
94 #include "progress.h"
95 #include "base64.h"
96 #include "upload.h"
97 #include "cookie.h"
99 #define _MPRINTF_REPLACE /* use our functions only */
100 #include <curl/mprintf.h>
103 * This function checks the linked list of custom HTTP headers for a particular
104 * header (prefix).
106 bool static checkheaders(struct UrlData *data, char *thisheader)
108 struct HttpHeader *head;
109 size_t thislen = strlen(thisheader);
111 for(head = data->headers; head; head=head->next) {
112 if(strnequal(head->header, thisheader, thislen)) {
113 return TRUE;
116 return FALSE;
119 UrgError http(struct UrlData *data, char *ppath, char *host, long *bytecount)
121 /* Send the GET line to the HTTP server */
123 struct FormData *sendit=NULL;
124 int postsize=0;
125 UrgError result;
126 char *buf;
127 struct Cookie *co = NULL;
128 char *p_pragma = NULL;
129 char *p_accept = NULL;
131 buf = data->buffer; /* this is our buffer */
133 if ( (data->conf&(CONF_HTTP|CONF_FTP)) &&
134 (data->conf&CONF_UPLOAD)) {
135 data->conf |= CONF_PUT;
137 #if 0 /* old version */
138 if((data->conf&(CONF_HTTP|CONF_UPLOAD)) ==
139 (CONF_HTTP|CONF_UPLOAD)) {
140 /* enable PUT! */
141 data->conf |= CONF_PUT;
143 #endif
145 /* The User-Agent string has been built in url.c already, because it might
146 have been used in the proxy connect, but if we have got a header with
147 the user-agent string specified, we erase the previosly made string
148 here. */
149 if(checkheaders(data, "User-Agent:") && data->ptr_uagent) {
150 free(data->ptr_uagent);
151 data->ptr_uagent=NULL;
154 if((data->conf & CONF_USERPWD) && !checkheaders(data, "Authorization:")) {
155 char authorization[512];
156 sprintf(data->buffer, "%s:%s", data->user, data->passwd);
157 base64Encode(data->buffer, authorization);
158 data->ptr_userpwd = maprintf( "Authorization: Basic %s\015\012",
159 authorization);
161 if((data->conf & CONF_RANGE) && !checkheaders(data, "Range:")) {
162 data->ptr_rangeline = maprintf("Range: bytes=%s\015\012", data->range);
164 if((data->conf & CONF_REFERER) && !checkheaders(data, "Referer:")) {
165 data->ptr_ref = maprintf("Referer: %s\015\012", data->referer);
167 if(data->cookie && !checkheaders(data, "Cookie:")) {
168 data->ptr_cookie = maprintf("Cookie: %s\015\012", data->cookie);
171 if(data->cookies) {
172 co = cookie_getlist(data->cookies,
173 host,
174 ppath,
175 data->conf&CONF_HTTPS?TRUE:FALSE);
177 if ((data->conf & CONF_PROXY) && (!(data->conf & CONF_HTTPS))) {
178 /* The path sent to the proxy is in fact the entire URL */
179 strncpy(ppath, data->url, URL_MAX_LENGTH-1);
181 if(data->conf & CONF_HTTPPOST) {
182 /* we must build the whole darned post sequence first, so that we have
183 a size of the whole shebang before we start to send it */
184 sendit = getFormData(data->httppost, &postsize);
187 if(!checkheaders(data, "Host:"))
188 data->ptr_host = maprintf("Host: %s\r\n", host);
191 if(!checkheaders(data, "Pragma:"))
192 p_pragma = "Pragma: no-cache\r\n";
194 if(!checkheaders(data, "Accept:"))
195 p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n";
197 do {
198 sendf(data->firstsocket, data,
199 "%s " /* GET/HEAD/POST/PUT */
200 "%s HTTP/1.0\r\n" /* path */
201 "%s" /* proxyuserpwd */
202 "%s" /* userpwd */
203 "%s" /* range */
204 "%s" /* user agent */
205 "%s" /* cookie */
206 "%s" /* host */
207 "%s" /* pragma */
208 "%s" /* accept */
209 "%s", /* referer */
211 data->customrequest?data->customrequest:
212 (data->conf&CONF_NOBODY?"HEAD":
213 (data->conf&(CONF_POST|CONF_HTTPPOST))?"POST":
214 (data->conf&CONF_PUT)?"PUT":"GET"),
215 ppath,
216 (data->conf&CONF_PROXYUSERPWD && data->ptr_proxyuserpwd)?data->ptr_proxyuserpwd:"",
217 (data->conf&CONF_USERPWD && data->ptr_userpwd)?data->ptr_userpwd:"",
218 (data->conf&CONF_RANGE && data->ptr_rangeline)?data->ptr_rangeline:"",
219 (data->useragent && *data->useragent && data->ptr_uagent)?data->ptr_uagent:"",
220 (data->ptr_cookie?data->ptr_cookie:""), /* Cookie: <data> */
221 (data->ptr_host?data->ptr_host:""), /* Host: host */
222 p_pragma?p_pragma:"",
223 p_accept?p_accept:"",
224 (data->conf&CONF_REFERER && data->ptr_ref)?data->ptr_ref:"" /* Referer: <data> <CRLF> */
227 if(co) {
228 int count=0;
229 /* now loop through all cookies that matched */
230 while(co) {
231 if(0 == count) {
232 sendf(data->firstsocket, data,
233 "Cookie: ");
235 count++;
236 sendf(data->firstsocket, data,
237 "%s=%s;", co->name, co->value);
238 co = co->next; /* next cookie please */
240 if(count) {
241 sendf(data->firstsocket, data,
242 "\r\n");
244 cookie_freelist(co); /* free the cookie list */
245 co=NULL;
248 if(data->timecondition) {
249 struct tm *thistime;
251 thistime = localtime(&data->timevalue);
253 #if defined(HAVE_STRFTIME) || defined(WIN32)
254 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
255 strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S %Z", thistime);
256 #else
257 /* Right, we *could* write a replacement here */
258 strcpy(buf, "no strftime() support");
259 #endif
260 switch(data->timecondition) {
261 case TIMECOND_IFMODSINCE:
262 default:
263 sendf(data->firstsocket, data,
264 "If-Modified-Since: %s\r\n", buf);
265 break;
266 case TIMECOND_IFUNMODSINCE:
267 sendf(data->firstsocket, data,
268 "If-Unmodified-Since: %s\r\n", buf);
269 break;
270 case TIMECOND_LASTMOD:
271 sendf(data->firstsocket, data,
272 "Last-Modified: %s\r\n", buf);
273 break;
277 while(data->headers) {
278 sendf(data->firstsocket, data,
279 "%s\015\012",
280 data->headers->header);
281 data->headers = data->headers->next;
284 if(data->conf&(CONF_POST|CONF_HTTPPOST)) {
285 if(data->conf & CONF_POST) {
286 /* this is the simple x-www-form-urlencoded style */
287 sendf(data->firstsocket, data,
288 "Content-Length: %d\015\012"
289 "Content-Type: application/x-www-form-urlencoded\r\n\r\n"
290 "%s\015\012",
291 strlen(data->postfields),
292 data->postfields );
294 else {
295 struct Form form;
296 size_t (*storefread)(char *, size_t , size_t , FILE *);
297 FILE *in;
298 long conf;
300 if(FormInit(&form, sendit)) {
301 failf(data, "Internal HTTP POST error!\n");
302 return URG_HTTP_POST_ERROR;
305 storefread = data->fread; /* backup */
306 in = data->in; /* backup */
308 data->fread =
309 (size_t (*)(char *, size_t, size_t, FILE *))
310 FormReader; /* set the read function to read from the
311 generated form data */
312 data->in = (FILE *)&form;
314 sendf(data->firstsocket, data,
315 "Content-Length: %d\r\n",
316 postsize-2);
318 conf = data->conf;
319 data->conf &= ~CONF_NOPROGRESS; /* enable progress meter */
320 ProgressInit(data, postsize);
322 result = Upload(data, data->firstsocket, bytecount);
324 FormFree(sendit); /* Now free that whole lot */
326 data->conf = conf; /* restore conf values for the download */
328 if(result)
329 return result;
331 data->fread = storefread; /* restore */
332 data->in = in; /* restore */
334 sendf(data->firstsocket, data,
335 "\r\n\r\n");
338 else if(data->conf&CONF_PUT) {
339 /* Let's PUT the data to the server! */
340 long conf;
342 if(data->infilesize>0) {
343 sendf(data->firstsocket, data,
344 "Content-Length: %d\r\n\r\n", /* file size */
345 data->infilesize );
347 else
348 sendf(data->firstsocket, data,
349 "\015\012");
351 conf = data->conf;
352 data->conf &= ~CONF_NOPROGRESS; /* enable progress meter */
354 ProgressInit(data, data->infilesize);
356 result = Upload(data, data->firstsocket, bytecount);
358 data->conf = conf;
360 if(result)
361 return result;
363 /* reset the byte counter */
364 *bytecount=0;
366 else {
367 sendf(data->firstsocket, data, "\r\n");
369 /* HTTP GET/HEAD download: */
370 result = Download(data, data->firstsocket, -1, TRUE, bytecount);
372 if(result)
373 return result;
375 ProgressEnd(data);
376 } while (0); /* this is just a left-over from the multiple document download
377 attempts */
379 return URG_OK;