1 /*****************************************************************************
3 * Project ___| | | | _ \| |
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
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 * ------------------------------------------------------------
27 * - Daniel Stenberg <Daniel.Stenberg@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 $
38 * ------------------------------------------------------------
39 ****************************************************************************/
41 /* -- WIN32 approved -- */
47 #include <sys/types.h>
54 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
62 #include <netinet/in.h>
64 #include <sys/resource.h>
69 #ifdef HAVE_ARPA_INET_H
70 #include <arpa/inet.h>
75 #include <sys/ioctl.h>
78 #ifdef HAVE_SYS_PARAM_H
79 #include <sys/param.h>
82 #ifdef HAVE_SYS_SELECT_H
83 #include <sys/select.h>
90 #include <curl/curl.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
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
)) {
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
;
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
)) {
141 data
->conf
|= CONF_PUT
;
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
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",
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
);
172 co
= cookie_getlist(data
->cookies
,
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";
198 sendf(data
->firstsocket
, data
,
199 "%s " /* GET/HEAD/POST/PUT */
200 "%s HTTP/1.0\r\n" /* path */
201 "%s" /* proxyuserpwd */
204 "%s" /* user agent */
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"),
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> */
229 /* now loop through all cookies that matched */
232 sendf(data
->firstsocket
, data
,
236 sendf(data
->firstsocket
, data
,
237 "%s=%s;", co
->name
, co
->value
);
238 co
= co
->next
; /* next cookie please */
241 sendf(data
->firstsocket
, data
,
244 cookie_freelist(co
); /* free the cookie list */
248 if(data
->timecondition
) {
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
);
257 /* Right, we *could* write a replacement here */
258 strcpy(buf
, "no strftime() support");
260 switch(data
->timecondition
) {
261 case TIMECOND_IFMODSINCE
:
263 sendf(data
->firstsocket
, data
,
264 "If-Modified-Since: %s\r\n", buf
);
266 case TIMECOND_IFUNMODSINCE
:
267 sendf(data
->firstsocket
, data
,
268 "If-Unmodified-Since: %s\r\n", buf
);
270 case TIMECOND_LASTMOD
:
271 sendf(data
->firstsocket
, data
,
272 "Last-Modified: %s\r\n", buf
);
277 while(data
->headers
) {
278 sendf(data
->firstsocket
, data
,
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"
291 strlen(data
->postfields
),
296 size_t (*storefread
)(char *, size_t , size_t , FILE *);
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 */
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",
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 */
331 data
->fread
= storefread
; /* restore */
332 data
->in
= in
; /* restore */
334 sendf(data
->firstsocket
, data
,
338 else if(data
->conf
&CONF_PUT
) {
339 /* Let's PUT the data to the server! */
342 if(data
->infilesize
>0) {
343 sendf(data
->firstsocket
, data
,
344 "Content-Length: %d\r\n\r\n", /* file size */
348 sendf(data
->firstsocket
, data
,
352 data
->conf
&= ~CONF_NOPROGRESS
; /* enable progress meter */
354 ProgressInit(data
, data
->infilesize
);
356 result
= Upload(data
, data
->firstsocket
, bytecount
);
363 /* reset the byte counter */
367 sendf(data
->firstsocket
, data
, "\r\n");
369 /* HTTP GET/HEAD download: */
370 result
= Download(data
, data
->firstsocket
, -1, TRUE
, bytecount
);
376 } while (0); /* this is just a left-over from the multiple document download