]>
Commit | Line | Data |
---|---|---|
3840d6ba | 1 | /* |
92e48f04 | 2 | * "$Id: http.c,v 1.82.2.32 2003/05/09 16:06:43 mike Exp $" |
3840d6ba | 3 | * |
99de6da0 | 4 | * HTTP routines for the Common UNIX Printing System (CUPS). |
fd8b1cf8 | 5 | * |
1d9595ab | 6 | * Copyright 1997-2003 by Easy Software Products, all rights reserved. |
fd8b1cf8 | 7 | * |
b38fb7fc | 8 | * These coded instructions, statements, and computer programs are the |
fd8b1cf8 | 9 | * property of Easy Software Products and are protected by Federal |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
fd8b1cf8 | 18 | * Hollywood, Maryland 20636-3111 USA |
19 | * | |
20 | * Voice: (301) 373-9603 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
3840d6ba | 23 | * |
dab1a4d8 | 24 | * This file is subject to the Apple OS-Developed Software exception. |
25 | * | |
3840d6ba | 26 | * Contents: |
27 | * | |
b5cb0608 | 28 | * httpInitialize() - Initialize the HTTP interface library and set the |
29 | * default HTTP proxy (if any). | |
30 | * httpCheck() - Check to see if there is a pending response from | |
31 | * the server. | |
d40085f1 | 32 | * httpClearCookie() - Clear the cookie value(s). |
b5cb0608 | 33 | * httpClose() - Close an HTTP connection... |
34 | * httpConnect() - Connect to a HTTP server. | |
35 | * httpConnectEncrypt() - Connect to a HTTP server using encryption. | |
36 | * httpEncryption() - Set the required encryption on the link. | |
37 | * httpReconnect() - Reconnect to a HTTP server... | |
b5cb0608 | 38 | * httpSetField() - Set the value of an HTTP header. |
39 | * httpDelete() - Send a DELETE request to the server. | |
40 | * httpGet() - Send a GET request to the server. | |
41 | * httpHead() - Send a HEAD request to the server. | |
42 | * httpOptions() - Send an OPTIONS request to the server. | |
43 | * httpPost() - Send a POST request to the server. | |
44 | * httpPut() - Send a PUT request to the server. | |
45 | * httpTrace() - Send an TRACE request to the server. | |
46 | * httpFlush() - Flush data from a HTTP connection. | |
47 | * httpRead() - Read data from a HTTP connection. | |
d40085f1 | 48 | * httpSetCookie() - Set the cookie value(s)... |
2e32fcdb | 49 | * httpWait() - Wait for data available on a connection. |
b5cb0608 | 50 | * httpWrite() - Write data to a HTTP connection. |
51 | * httpGets() - Get a line of text from a HTTP connection. | |
52 | * httpPrintf() - Print a formatted string to a HTTP connection. | |
53 | * httpStatus() - Return a short string describing a HTTP status code. | |
54 | * httpGetDateString() - Get a formatted date/time string from a time value. | |
55 | * httpGetDateTime() - Get a time value from a formatted date/time string. | |
56 | * httpUpdate() - Update the current HTTP state for incoming data. | |
57 | * httpDecode64() - Base64-decode a string. | |
58 | * httpEncode64() - Base64-encode a string. | |
59 | * httpGetLength() - Get the amount of data remaining from the | |
60 | * content-length or transfer-encoding fields. | |
61 | * http_field() - Return the field index for a field name. | |
62 | * http_send() - Send a request with all fields and the trailing | |
63 | * blank line. | |
64 | * http_upgrade() - Force upgrade to TLS encryption. | |
bcf61448 | 65 | * http_setup_ssl() - Set up SSL/TLS on a connection. |
66 | * http_shutdown_ssl() - Shut down SSL/TLS on a connection. | |
67 | * http_read_ssl() - Read from a SSL/TLS connection. | |
68 | * http_write_ssl() - Write to a SSL/TLS connection. | |
dcfcaeac | 69 | * CDSAReadFunc() - Read function for CDSA decryption code. |
70 | * CDSAWriteFunc() - Write function for CDSA encryption code. | |
3840d6ba | 71 | */ |
72 | ||
73 | /* | |
74 | * Include necessary headers... | |
75 | */ | |
76 | ||
3b960317 | 77 | #include <stdio.h> |
78 | #include <stdlib.h> | |
3840d6ba | 79 | #include <stdarg.h> |
3b960317 | 80 | #include <ctype.h> |
81 | #include "string.h" | |
3b960317 | 82 | #include <fcntl.h> |
4e8f6c6a | 83 | #include <errno.h> |
992cf15a | 84 | |
bcf61448 | 85 | #include "http-private.h" |
8a5aa628 | 86 | #include "ipp.h" |
4a73831b | 87 | #include "debug.h" |
f4cafe91 | 88 | |
c3026ddc | 89 | #ifndef WIN32 |
5356dc5a | 90 | # include <signal.h> |
63d94476 | 91 | # include <sys/time.h> |
92 | # include <sys/resource.h> | |
c3026ddc | 93 | #endif /* !WIN32 */ |
5356dc5a | 94 | |
a75c006a | 95 | |
42d48bd2 | 96 | /* |
97 | * Some operating systems have done away with the Fxxxx constants for | |
98 | * the fcntl() call; this works around that "feature"... | |
99 | */ | |
100 | ||
101 | #ifndef FNONBLK | |
102 | # define FNONBLK O_NONBLOCK | |
103 | #endif /* !FNONBLK */ | |
104 | ||
992cf15a | 105 | |
106 | /* | |
3a193f5e | 107 | * Local functions... |
992cf15a | 108 | */ |
109 | ||
063e1ac7 | 110 | static http_field_t http_field(const char *name); |
111 | static int http_send(http_t *http, http_state_t request, | |
112 | const char *uri); | |
bcf61448 | 113 | #ifdef HAVE_SSL |
2a0ef17a | 114 | static int http_upgrade(http_t *http); |
bcf61448 | 115 | static int http_setup_ssl(http_t *http); |
116 | static void http_shutdown_ssl(http_t *http); | |
117 | static int http_read_ssl(http_t *http, char *buf, int len); | |
118 | static int http_write_ssl(http_t *http, const char *buf, int len); | |
dcfcaeac | 119 | # ifdef HAVE_CDSASSL |
120 | static OSStatus CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength); | |
121 | static OSStatus CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength); | |
122 | # endif /* HAVE_CDSASSL */ | |
bcf61448 | 123 | #endif /* HAVE_SSL */ |
3840d6ba | 124 | |
125 | ||
126 | /* | |
3a193f5e | 127 | * Local globals... |
3840d6ba | 128 | */ |
129 | ||
6db7190f | 130 | static const char * const http_fields[] = |
3a193f5e | 131 | { |
3a193f5e | 132 | "Accept-Language", |
0542e38e | 133 | "Accept-Ranges", |
3a193f5e | 134 | "Authorization", |
3a193f5e | 135 | "Connection", |
3a193f5e | 136 | "Content-Encoding", |
137 | "Content-Language", | |
138 | "Content-Length", | |
139 | "Content-Location", | |
140 | "Content-MD5", | |
141 | "Content-Range", | |
142 | "Content-Type", | |
0d1f75a3 | 143 | "Content-Version", |
3a193f5e | 144 | "Date", |
3a193f5e | 145 | "Host", |
3a193f5e | 146 | "If-Modified-Since", |
3a193f5e | 147 | "If-Unmodified-since", |
0d1f75a3 | 148 | "Keep-Alive", |
3a193f5e | 149 | "Last-Modified", |
0d1f75a3 | 150 | "Link", |
3a193f5e | 151 | "Location", |
3a193f5e | 152 | "Range", |
153 | "Referer", | |
154 | "Retry-After", | |
3a193f5e | 155 | "Transfer-Encoding", |
156 | "Upgrade", | |
157 | "User-Agent", | |
3a193f5e | 158 | "WWW-Authenticate" |
159 | }; | |
6db7190f | 160 | static const char * const days[7] = |
3a193f5e | 161 | { |
162 | "Sun", | |
163 | "Mon", | |
164 | "Tue", | |
165 | "Wed", | |
166 | "Thu", | |
167 | "Fri", | |
168 | "Sat" | |
169 | }; | |
6db7190f | 170 | static const char * const months[12] = |
3a193f5e | 171 | { |
172 | "Jan", | |
173 | "Feb", | |
174 | "Mar", | |
175 | "Apr", | |
176 | "May", | |
177 | "Jun", | |
178 | "Jul", | |
179 | "Aug", | |
180 | "Sep", | |
181 | "Oct", | |
182 | "Nov", | |
183 | "Dec" | |
184 | }; | |
3840d6ba | 185 | |
186 | ||
9cba63f2 | 187 | /* |
188 | * 'httpInitialize()' - Initialize the HTTP interface library and set the | |
189 | * default HTTP proxy (if any). | |
190 | */ | |
191 | ||
192 | void | |
0542e38e | 193 | httpInitialize(void) |
9cba63f2 | 194 | { |
a75c006a | 195 | #ifdef HAVE_LIBSSL |
a75c006a | 196 | struct timeval curtime; /* Current time in microseconds */ |
1c6682dd | 197 | int i; /* Looping var */ |
198 | unsigned char data[1024]; /* Seed data */ | |
a75c006a | 199 | #endif /* HAVE_LIBSSL */ |
200 | ||
c3026ddc | 201 | #ifdef WIN32 |
50146867 | 202 | WSADATA winsockdata; /* WinSock data */ |
203 | static int initialized = 0;/* Has WinSock been initialized? */ | |
204 | ||
205 | ||
206 | if (!initialized) | |
207 | WSAStartup(MAKEWORD(1,1), &winsockdata); | |
ca7e65c8 | 208 | #elif defined(HAVE_SIGSET) |
209 | sigset(SIGPIPE, SIG_IGN); | |
210 | #elif defined(HAVE_SIGACTION) | |
2bffb563 | 211 | struct sigaction action; /* POSIX sigaction data */ |
212 | ||
213 | ||
214 | /* | |
215 | * Ignore SIGPIPE signals... | |
216 | */ | |
217 | ||
218 | memset(&action, 0, sizeof(action)); | |
219 | action.sa_handler = SIG_IGN; | |
220 | sigaction(SIGPIPE, &action, NULL); | |
ca7e65c8 | 221 | #else |
222 | signal(SIGPIPE, SIG_IGN); | |
c3026ddc | 223 | #endif /* WIN32 */ |
a75c006a | 224 | |
bcf61448 | 225 | #ifdef HAVE_GNUTLS |
226 | gnutls_global_init(); | |
227 | #endif /* HAVE_GNUTLS */ | |
228 | ||
a75c006a | 229 | #ifdef HAVE_LIBSSL |
1c6682dd | 230 | SSL_load_error_strings(); |
a75c006a | 231 | SSL_library_init(); |
232 | ||
233 | /* | |
234 | * Using the current time is a dubious random seed, but on some systems | |
235 | * it is the best we can do (on others, this seed isn't even used...) | |
236 | */ | |
237 | ||
a75c006a | 238 | gettimeofday(&curtime, NULL); |
1c6682dd | 239 | srand(curtime.tv_sec + curtime.tv_usec); |
240 | ||
241 | for (i = 0; i < sizeof(data); i ++) | |
242 | data[i] = rand(); /* Yes, this is a poor source of random data... */ | |
243 | ||
244 | RAND_seed(&data, sizeof(data)); | |
a75c006a | 245 | #endif /* HAVE_LIBSSL */ |
50146867 | 246 | } |
247 | ||
248 | ||
c1918ec5 | 249 | /* |
250 | * 'httpCheck()' - Check to see if there is a pending response from the server. | |
251 | */ | |
252 | ||
253 | int /* O - 0 = no data, 1 = data available */ | |
254 | httpCheck(http_t *http) /* I - HTTP connection */ | |
255 | { | |
2e32fcdb | 256 | return (httpWait(http, 0)); |
c1918ec5 | 257 | } |
258 | ||
259 | ||
d40085f1 | 260 | /* |
261 | * 'httpClearCookie()' - Clear the cookie value(s). | |
262 | */ | |
263 | ||
264 | void | |
265 | httpClearCookie(http_t *http) /* I - Connection */ | |
266 | { | |
267 | if (!http) | |
268 | return; | |
269 | ||
270 | if (http->cookie) | |
271 | { | |
272 | free(http->cookie); | |
273 | http->cookie = NULL; | |
274 | } | |
275 | } | |
276 | ||
277 | ||
50146867 | 278 | /* |
279 | * 'httpClose()' - Close an HTTP connection... | |
280 | */ | |
281 | ||
282 | void | |
283 | httpClose(http_t *http) /* I - Connection to close */ | |
284 | { | |
2a0ef17a | 285 | if (!http) |
50146867 | 286 | return; |
287 | ||
2e32fcdb | 288 | if (http->input_set) |
289 | free(http->input_set); | |
290 | ||
d40085f1 | 291 | if (http->cookie) |
292 | free(http->cookie); | |
293 | ||
bcf61448 | 294 | #ifdef HAVE_SSL |
2a0ef17a | 295 | if (http->tls) |
bcf61448 | 296 | http_shutdown_ssl(http); |
297 | #endif /* HAVE_SSL */ | |
2a0ef17a | 298 | |
50146867 | 299 | #ifdef WIN32 |
300 | closesocket(http->fd); | |
301 | #else | |
302 | close(http->fd); | |
303 | #endif /* WIN32 */ | |
304 | ||
305 | free(http); | |
9cba63f2 | 306 | } |
307 | ||
308 | ||
3840d6ba | 309 | /* |
50146867 | 310 | * 'httpConnect()' - Connect to a HTTP server. |
3840d6ba | 311 | */ |
312 | ||
50146867 | 313 | http_t * /* O - New HTTP connection */ |
063e1ac7 | 314 | httpConnect(const char *host, /* I - Host to connect to */ |
315 | int port) /* I - Port number */ | |
b5cb0608 | 316 | { |
317 | http_encryption_t encrypt;/* Type of encryption to use */ | |
318 | ||
319 | ||
320 | /* | |
321 | * Set the default encryption status... | |
322 | */ | |
323 | ||
324 | if (port == 443) | |
325 | encrypt = HTTP_ENCRYPT_ALWAYS; | |
326 | else | |
327 | encrypt = HTTP_ENCRYPT_IF_REQUESTED; | |
328 | ||
329 | return (httpConnectEncrypt(host, port, encrypt)); | |
330 | } | |
331 | ||
332 | ||
333 | /* | |
334 | * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption. | |
335 | */ | |
336 | ||
337 | http_t * /* O - New HTTP connection */ | |
338 | httpConnectEncrypt(const char *host, /* I - Host to connect to */ | |
339 | int port, /* I - Port number */ | |
340 | http_encryption_t encrypt) | |
341 | /* I - Type of encryption to use */ | |
3840d6ba | 342 | { |
99de6da0 | 343 | int i; /* Looping var */ |
50146867 | 344 | http_t *http; /* New HTTP connection */ |
345 | struct hostent *hostaddr; /* Host address data */ | |
346 | ||
347 | ||
db8c0a8c | 348 | if (host == NULL) |
349 | return (NULL); | |
350 | ||
0b83a6c8 | 351 | httpInitialize(); |
352 | ||
50146867 | 353 | /* |
354 | * Lookup the host... | |
355 | */ | |
356 | ||
753453e4 | 357 | if ((hostaddr = httpGetHostByName(host)) == NULL) |
627f4602 | 358 | { |
359 | /* | |
360 | * This hack to make users that don't have a localhost entry in | |
361 | * their hosts file or DNS happy... | |
362 | */ | |
363 | ||
364 | if (strcasecmp(host, "localhost") != 0) | |
365 | return (NULL); | |
753453e4 | 366 | else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL) |
627f4602 | 367 | return (NULL); |
368 | } | |
3840d6ba | 369 | |
7e9dc5e9 | 370 | /* |
371 | * Verify that it is an IPv4 address (IPv6 support will come in CUPS 1.2...) | |
372 | */ | |
373 | ||
99de6da0 | 374 | #ifdef AF_INET6 |
375 | if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4) && | |
376 | (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16)) | |
377 | return (NULL); | |
378 | #else | |
7e9dc5e9 | 379 | if (hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4) |
380 | return (NULL); | |
99de6da0 | 381 | #endif /* AF_INET6 */ |
7e9dc5e9 | 382 | |
3840d6ba | 383 | /* |
3a193f5e | 384 | * Allocate memory for the structure... |
3840d6ba | 385 | */ |
386 | ||
3a193f5e | 387 | http = calloc(sizeof(http_t), 1); |
388 | if (http == NULL) | |
389 | return (NULL); | |
3840d6ba | 390 | |
a8374e1e | 391 | http->version = HTTP_1_1; |
0542e38e | 392 | http->blocking = 1; |
3a193f5e | 393 | http->activity = time(NULL); |
7e9dc5e9 | 394 | http->fd = -1; |
3840d6ba | 395 | |
b5cb0608 | 396 | /* |
397 | * Set the encryption status... | |
398 | */ | |
399 | ||
753453e4 | 400 | if (port == 443) /* Always use encryption for https */ |
401 | http->encryption = HTTP_ENCRYPT_ALWAYS; | |
402 | else | |
403 | http->encryption = encrypt; | |
b5cb0608 | 404 | |
a75c006a | 405 | /* |
99de6da0 | 406 | * Loop through the addresses we have until one of them connects... |
a75c006a | 407 | */ |
408 | ||
def978d5 | 409 | strlcpy(http->hostname, host, sizeof(http->hostname)); |
07c5adda | 410 | |
99de6da0 | 411 | for (i = 0; hostaddr->h_addr_list[i]; i ++) |
412 | { | |
413 | /* | |
414 | * Load the address... | |
415 | */ | |
416 | ||
417 | httpAddrLoad(hostaddr, port, i, &(http->hostaddr)); | |
418 | ||
419 | /* | |
420 | * Connect to the remote system... | |
421 | */ | |
422 | ||
423 | if (!httpReconnect(http)) | |
424 | break; | |
425 | } | |
426 | ||
427 | /* | |
428 | * Return the new structure if we could connect; otherwise, bail out... | |
429 | */ | |
430 | ||
431 | if (hostaddr->h_addr_list[i]) | |
432 | return (http); | |
433 | else | |
3840d6ba | 434 | { |
3a193f5e | 435 | free(http); |
436 | return (NULL); | |
3840d6ba | 437 | } |
3a193f5e | 438 | } |
3840d6ba | 439 | |
3840d6ba | 440 | |
b38fb7fc | 441 | /* |
442 | * 'httpEncryption()' - Set the required encryption on the link. | |
443 | */ | |
444 | ||
445 | int /* O - -1 on error, 0 on success */ | |
446 | httpEncryption(http_t *http, /* I - HTTP data */ | |
447 | http_encryption_t e) /* I - New encryption preference */ | |
448 | { | |
bcf61448 | 449 | #ifdef HAVE_SSL |
b38fb7fc | 450 | if (!http) |
2a0ef17a | 451 | return (0); |
b38fb7fc | 452 | |
453 | http->encryption = e; | |
454 | ||
455 | if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) || | |
456 | (http->encryption == HTTP_ENCRYPT_NEVER && http->tls)) | |
457 | return (httpReconnect(http)); | |
2a0ef17a | 458 | else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) |
459 | return (http_upgrade(http)); | |
460 | else | |
461 | return (0); | |
462 | #else | |
463 | if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED) | |
464 | return (-1); | |
b38fb7fc | 465 | else |
466 | return (0); | |
bcf61448 | 467 | #endif /* HAVE_SSL */ |
b38fb7fc | 468 | } |
469 | ||
470 | ||
3a193f5e | 471 | /* |
50146867 | 472 | * 'httpReconnect()' - Reconnect to a HTTP server... |
3a193f5e | 473 | */ |
3840d6ba | 474 | |
50146867 | 475 | int /* O - 0 on success, non-zero on failure */ |
476 | httpReconnect(http_t *http) /* I - HTTP data */ | |
3a193f5e | 477 | { |
a75c006a | 478 | int val; /* Socket option value */ |
3840d6ba | 479 | |
bcf61448 | 480 | #ifdef HAVE_SSL |
a75c006a | 481 | if (http->tls) |
bcf61448 | 482 | http_shutdown_ssl(http); |
483 | #endif /* HAVE_SSL */ | |
a75c006a | 484 | |
50146867 | 485 | /* |
486 | * Close any previously open socket... | |
487 | */ | |
488 | ||
7e9dc5e9 | 489 | if (http->fd >= 0) |
3a193f5e | 490 | #ifdef WIN32 |
50146867 | 491 | closesocket(http->fd); |
3a193f5e | 492 | #else |
50146867 | 493 | close(http->fd); |
3a193f5e | 494 | #endif /* WIN32 */ |
3840d6ba | 495 | |
50146867 | 496 | /* |
497 | * Create the socket and set options to allow reuse. | |
498 | */ | |
3840d6ba | 499 | |
99de6da0 | 500 | if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0) |
0bf5ae82 | 501 | { |
c3026ddc | 502 | #ifdef WIN32 |
977acbd3 | 503 | http->error = WSAGetLastError(); |
504 | #else | |
f44afac9 | 505 | http->error = errno; |
c3026ddc | 506 | #endif /* WIN32 */ |
f44afac9 | 507 | http->status = HTTP_ERROR; |
50146867 | 508 | return (-1); |
0bf5ae82 | 509 | } |
fd8b1cf8 | 510 | |
50146867 | 511 | #ifdef FD_CLOEXEC |
512 | fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting * | |
513 | * other processes... */ | |
514 | #endif /* FD_CLOEXEC */ | |
fd8b1cf8 | 515 | |
50146867 | 516 | val = 1; |
2456b740 | 517 | setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); |
3840d6ba | 518 | |
50146867 | 519 | #ifdef SO_REUSEPORT |
520 | val = 1; | |
521 | setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); | |
522 | #endif /* SO_REUSEPORT */ | |
3840d6ba | 523 | |
9ae34eb7 | 524 | /* |
525 | * Using TCP_NODELAY improves responsiveness, especially on systems | |
526 | * with a slow loopback interface... Since we write large buffers | |
527 | * when sending print files and requests, there shouldn't be any | |
528 | * performance penalty for this... | |
529 | */ | |
530 | ||
531 | val = 1; | |
532 | setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); | |
533 | ||
50146867 | 534 | /* |
535 | * Connect to the server... | |
536 | */ | |
537 | ||
a09840c5 | 538 | #ifdef AF_INET6 |
539 | if (connect(http->fd, (struct sockaddr *)&(http->hostaddr), | |
540 | http->hostaddr.addr.sa_family == AF_INET ? | |
541 | sizeof(http->hostaddr.ipv4) : | |
542 | sizeof(http->hostaddr.ipv6)) < 0) | |
543 | #else | |
50146867 | 544 | if (connect(http->fd, (struct sockaddr *)&(http->hostaddr), |
a09840c5 | 545 | sizeof(http->hostaddr.ipv4)) < 0) |
546 | #endif /* AF_INET6 */ | |
50146867 | 547 | { |
c3026ddc | 548 | #ifdef WIN32 |
977acbd3 | 549 | http->error = WSAGetLastError(); |
550 | #else | |
f44afac9 | 551 | http->error = errno; |
c3026ddc | 552 | #endif /* WIN32 */ |
f44afac9 | 553 | http->status = HTTP_ERROR; |
0bf5ae82 | 554 | |
50146867 | 555 | #ifdef WIN32 |
556 | closesocket(http->fd); | |
557 | #else | |
558 | close(http->fd); | |
559 | #endif | |
560 | ||
7e9dc5e9 | 561 | http->fd = -1; |
562 | ||
50146867 | 563 | return (-1); |
e8fda7b9 | 564 | } |
f44afac9 | 565 | |
566 | http->error = 0; | |
567 | http->status = HTTP_CONTINUE; | |
50146867 | 568 | |
bcf61448 | 569 | #ifdef HAVE_SSL |
a75c006a | 570 | if (http->encryption == HTTP_ENCRYPT_ALWAYS) |
571 | { | |
572 | /* | |
2a0ef17a | 573 | * Always do encryption via SSL. |
a75c006a | 574 | */ |
575 | ||
bcf61448 | 576 | if (http_setup_ssl(http) != 0) |
a75c006a | 577 | { |
a75c006a | 578 | #ifdef WIN32 |
579 | closesocket(http->fd); | |
580 | #else | |
581 | close(http->fd); | |
bcf61448 | 582 | #endif /* WIN32 */ |
a75c006a | 583 | |
584 | return (-1); | |
585 | } | |
a75c006a | 586 | } |
2a0ef17a | 587 | else if (http->encryption == HTTP_ENCRYPT_REQUIRED) |
588 | return (http_upgrade(http)); | |
bcf61448 | 589 | #endif /* HAVE_SSL */ |
a75c006a | 590 | |
50146867 | 591 | return (0); |
3a193f5e | 592 | } |
593 | ||
594 | ||
83e740a5 | 595 | /* |
596 | * 'httpGetSubField()' - Get a sub-field value. | |
597 | */ | |
598 | ||
599 | char * /* O - Value or NULL */ | |
600 | httpGetSubField(http_t *http, /* I - HTTP data */ | |
601 | http_field_t field, /* I - Field index */ | |
602 | const char *name, /* I - Name of sub-field */ | |
603 | char *value) /* O - Value string */ | |
604 | { | |
605 | const char *fptr; /* Pointer into field */ | |
606 | char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */ | |
607 | *ptr; /* Pointer into string buffer */ | |
608 | ||
609 | ||
610 | if (http == NULL || | |
611 | field < HTTP_FIELD_ACCEPT_LANGUAGE || | |
612 | field > HTTP_FIELD_WWW_AUTHENTICATE || | |
613 | name == NULL || value == NULL) | |
614 | return (NULL); | |
615 | ||
616 | for (fptr = http->fields[field]; *fptr;) | |
617 | { | |
618 | /* | |
619 | * Skip leading whitespace... | |
620 | */ | |
621 | ||
3f4c4837 | 622 | while (isspace(*fptr)) |
83e740a5 | 623 | fptr ++; |
624 | ||
625 | if (*fptr == ',') | |
626 | { | |
627 | fptr ++; | |
628 | continue; | |
629 | } | |
630 | ||
631 | /* | |
632 | * Get the sub-field name... | |
633 | */ | |
634 | ||
635 | for (ptr = temp; | |
636 | *fptr && *fptr != '=' && !isspace(*fptr) && ptr < (temp + sizeof(temp) - 1); | |
637 | *ptr++ = *fptr++); | |
638 | ||
639 | *ptr = '\0'; | |
640 | ||
641 | /* | |
642 | * Skip trailing chars up to the '='... | |
643 | */ | |
644 | ||
645 | while (*fptr && *fptr != '=') | |
646 | fptr ++; | |
647 | ||
648 | if (!*fptr) | |
649 | break; | |
650 | ||
651 | /* | |
652 | * Skip = and leading whitespace... | |
653 | */ | |
654 | ||
655 | fptr ++; | |
656 | ||
3f4c4837 | 657 | while (isspace(*fptr)) |
83e740a5 | 658 | fptr ++; |
659 | ||
660 | if (*fptr == '\"') | |
661 | { | |
662 | /* | |
663 | * Read quoted string... | |
664 | */ | |
665 | ||
666 | for (ptr = value, fptr ++; | |
667 | *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1); | |
668 | *ptr++ = *fptr++); | |
669 | ||
670 | *ptr = '\0'; | |
671 | ||
672 | while (*fptr && *fptr != '\"') | |
673 | fptr ++; | |
674 | ||
675 | if (*fptr) | |
676 | fptr ++; | |
677 | } | |
678 | else | |
679 | { | |
680 | /* | |
681 | * Read unquoted string... | |
682 | */ | |
683 | ||
684 | for (ptr = value; | |
685 | *fptr && !isspace(*fptr) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1); | |
686 | *ptr++ = *fptr++); | |
687 | ||
688 | *ptr = '\0'; | |
689 | ||
690 | while (*fptr && !isspace(*fptr) && *fptr != ',') | |
691 | fptr ++; | |
692 | } | |
693 | ||
694 | /* | |
695 | * See if this is the one... | |
696 | */ | |
697 | ||
698 | if (strcmp(name, temp) == 0) | |
699 | return (value); | |
700 | } | |
701 | ||
702 | value[0] = '\0'; | |
703 | ||
704 | return (NULL); | |
705 | } | |
706 | ||
707 | ||
50146867 | 708 | /* |
709 | * 'httpSetField()' - Set the value of an HTTP header. | |
710 | */ | |
3a193f5e | 711 | |
50146867 | 712 | void |
713 | httpSetField(http_t *http, /* I - HTTP data */ | |
714 | http_field_t field, /* I - Field index */ | |
063e1ac7 | 715 | const char *value) /* I - Value */ |
3a193f5e | 716 | { |
83e740a5 | 717 | if (http == NULL || |
718 | field < HTTP_FIELD_ACCEPT_LANGUAGE || | |
719 | field > HTTP_FIELD_WWW_AUTHENTICATE || | |
720 | value == NULL) | |
721 | return; | |
722 | ||
def978d5 | 723 | strlcpy(http->fields[field], value, HTTP_MAX_VALUE); |
3a193f5e | 724 | } |
725 | ||
726 | ||
50146867 | 727 | /* |
728 | * 'httpDelete()' - Send a DELETE request to the server. | |
729 | */ | |
730 | ||
731 | int /* O - Status of call (0 = success) */ | |
063e1ac7 | 732 | httpDelete(http_t *http, /* I - HTTP data */ |
733 | const char *uri) /* I - URI to delete */ | |
3a193f5e | 734 | { |
a8374e1e | 735 | return (http_send(http, HTTP_DELETE, uri)); |
3a193f5e | 736 | } |
737 | ||
738 | ||
50146867 | 739 | /* |
740 | * 'httpGet()' - Send a GET request to the server. | |
741 | */ | |
742 | ||
743 | int /* O - Status of call (0 = success) */ | |
063e1ac7 | 744 | httpGet(http_t *http, /* I - HTTP data */ |
745 | const char *uri) /* I - URI to get */ | |
3a193f5e | 746 | { |
a8374e1e | 747 | return (http_send(http, HTTP_GET, uri)); |
3a193f5e | 748 | } |
749 | ||
750 | ||
50146867 | 751 | /* |
752 | * 'httpHead()' - Send a HEAD request to the server. | |
753 | */ | |
754 | ||
755 | int /* O - Status of call (0 = success) */ | |
063e1ac7 | 756 | httpHead(http_t *http, /* I - HTTP data */ |
757 | const char *uri) /* I - URI for head */ | |
3a193f5e | 758 | { |
a8374e1e | 759 | return (http_send(http, HTTP_HEAD, uri)); |
3a193f5e | 760 | } |
761 | ||
762 | ||
50146867 | 763 | /* |
764 | * 'httpOptions()' - Send an OPTIONS request to the server. | |
765 | */ | |
766 | ||
767 | int /* O - Status of call (0 = success) */ | |
063e1ac7 | 768 | httpOptions(http_t *http, /* I - HTTP data */ |
769 | const char *uri) /* I - URI for options */ | |
3a193f5e | 770 | { |
a8374e1e | 771 | return (http_send(http, HTTP_OPTIONS, uri)); |
3a193f5e | 772 | } |
773 | ||
774 | ||
50146867 | 775 | /* |
776 | * 'httpPost()' - Send a POST request to the server. | |
777 | */ | |
778 | ||
779 | int /* O - Status of call (0 = success) */ | |
063e1ac7 | 780 | httpPost(http_t *http, /* I - HTTP data */ |
781 | const char *uri) /* I - URI for post */ | |
3a193f5e | 782 | { |
4a73831b | 783 | httpGetLength(http); |
0542e38e | 784 | |
a8374e1e | 785 | return (http_send(http, HTTP_POST, uri)); |
3a193f5e | 786 | } |
787 | ||
788 | ||
789 | /* | |
50146867 | 790 | * 'httpPut()' - Send a PUT request to the server. |
3a193f5e | 791 | */ |
792 | ||
50146867 | 793 | int /* O - Status of call (0 = success) */ |
063e1ac7 | 794 | httpPut(http_t *http, /* I - HTTP data */ |
795 | const char *uri) /* I - URI to put */ | |
3a193f5e | 796 | { |
4a73831b | 797 | httpGetLength(http); |
0542e38e | 798 | |
a8374e1e | 799 | return (http_send(http, HTTP_PUT, uri)); |
3840d6ba | 800 | } |
801 | ||
802 | ||
803 | /* | |
50146867 | 804 | * 'httpTrace()' - Send an TRACE request to the server. |
3840d6ba | 805 | */ |
806 | ||
50146867 | 807 | int /* O - Status of call (0 = success) */ |
063e1ac7 | 808 | httpTrace(http_t *http, /* I - HTTP data */ |
809 | const char *uri) /* I - URI for trace */ | |
3840d6ba | 810 | { |
a8374e1e | 811 | return (http_send(http, HTTP_TRACE, uri)); |
3840d6ba | 812 | } |
813 | ||
814 | ||
69ee1496 | 815 | /* |
816 | * 'httpFlush()' - Flush data from a HTTP connection. | |
817 | */ | |
818 | ||
819 | void | |
820 | httpFlush(http_t *http) /* I - HTTP data */ | |
821 | { | |
822 | char buffer[8192]; /* Junk buffer */ | |
823 | ||
824 | ||
dd63ebe2 | 825 | if (http->state != HTTP_WAITING) |
826 | { | |
827 | while (httpRead(http, buffer, sizeof(buffer)) > 0); | |
828 | } | |
69ee1496 | 829 | } |
830 | ||
831 | ||
3840d6ba | 832 | /* |
50146867 | 833 | * 'httpRead()' - Read data from a HTTP connection. |
3840d6ba | 834 | */ |
835 | ||
50146867 | 836 | int /* O - Number of bytes read */ |
837 | httpRead(http_t *http, /* I - HTTP data */ | |
838 | char *buffer, /* I - Buffer for data */ | |
839 | int length) /* I - Maximum number of bytes */ | |
3840d6ba | 840 | { |
2456b740 | 841 | int bytes; /* Bytes read */ |
50146867 | 842 | char len[32]; /* Length string */ |
3840d6ba | 843 | |
844 | ||
0f33610c | 845 | DEBUG_printf(("httpRead(%p, %p, %d)\n", http, buffer, length)); |
4a73831b | 846 | |
50146867 | 847 | if (http == NULL || buffer == NULL) |
848 | return (-1); | |
3840d6ba | 849 | |
50146867 | 850 | http->activity = time(NULL); |
3840d6ba | 851 | |
50146867 | 852 | if (length <= 0) |
853 | return (0); | |
fd8b1cf8 | 854 | |
0542e38e | 855 | if (http->data_encoding == HTTP_ENCODE_CHUNKED && |
5e879034 | 856 | http->data_remaining <= 0) |
50146867 | 857 | { |
5e879034 | 858 | DEBUG_puts("httpRead: Getting chunk length..."); |
859 | ||
50146867 | 860 | if (httpGets(len, sizeof(len), http) == NULL) |
5e879034 | 861 | { |
862 | DEBUG_puts("httpRead: Could not get length!"); | |
50146867 | 863 | return (0); |
5e879034 | 864 | } |
3840d6ba | 865 | |
0542e38e | 866 | http->data_remaining = strtol(len, NULL, 16); |
901b295d | 867 | if (http->data_remaining < 0) |
868 | { | |
869 | DEBUG_puts("httpRead: Negative chunk length!"); | |
870 | return (0); | |
871 | } | |
50146867 | 872 | } |
3840d6ba | 873 | |
4a73831b | 874 | DEBUG_printf(("httpRead: data_remaining = %d\n", http->data_remaining)); |
875 | ||
901b295d | 876 | if (http->data_remaining <= 0) |
3840d6ba | 877 | { |
50146867 | 878 | /* |
879 | * A zero-length chunk ends a transfer; unless we are reading POST | |
880 | * data, go idle... | |
881 | */ | |
f736c0e3 | 882 | |
5e879034 | 883 | if (http->data_encoding == HTTP_ENCODE_CHUNKED) |
4355fb2f | 884 | httpGets(len, sizeof(len), http); |
885 | ||
50146867 | 886 | if (http->state == HTTP_POST_RECV) |
887 | http->state ++; | |
888 | else | |
889 | http->state = HTTP_WAITING; | |
3840d6ba | 890 | |
50146867 | 891 | return (0); |
892 | } | |
0542e38e | 893 | else if (length > http->data_remaining) |
894 | length = http->data_remaining; | |
50146867 | 895 | |
753453e4 | 896 | if (http->used == 0 && length <= 256) |
897 | { | |
898 | /* | |
899 | * Buffer small reads for better performance... | |
900 | */ | |
901 | ||
902 | if (http->data_remaining > sizeof(http->buffer)) | |
903 | bytes = sizeof(http->buffer); | |
904 | else | |
905 | bytes = http->data_remaining; | |
906 | ||
92e48f04 | 907 | if (!http->blocking && !httpWait(http, 1000)) |
908 | return (0); | |
909 | ||
bcf61448 | 910 | #ifdef HAVE_SSL |
753453e4 | 911 | if (http->tls) |
bcf61448 | 912 | bytes = http_read_ssl(http, http->buffer, bytes); |
753453e4 | 913 | else |
bcf61448 | 914 | #endif /* HAVE_SSL */ |
753453e4 | 915 | { |
916 | DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n", | |
917 | bytes)); | |
918 | ||
919 | bytes = recv(http->fd, http->buffer, bytes, 0); | |
920 | ||
921 | DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n", | |
922 | bytes)); | |
923 | } | |
924 | ||
925 | if (bytes > 0) | |
926 | http->used = bytes; | |
927 | else if (bytes < 0) | |
928 | { | |
c3026ddc | 929 | #ifdef WIN32 |
753453e4 | 930 | http->error = WSAGetLastError(); |
bdbaa675 | 931 | return (-1); |
753453e4 | 932 | #else |
bdbaa675 | 933 | if (errno != EINTR) |
934 | { | |
935 | http->error = errno; | |
936 | return (-1); | |
937 | } | |
c3026ddc | 938 | #endif /* WIN32 */ |
753453e4 | 939 | } |
92e48f04 | 940 | else if (bytes == 0) |
941 | { | |
942 | http->error = EPIPE; | |
753453e4 | 943 | return (0); |
92e48f04 | 944 | } |
753453e4 | 945 | } |
946 | ||
0542e38e | 947 | if (http->used > 0) |
50146867 | 948 | { |
0542e38e | 949 | if (length > http->used) |
950 | length = http->used; | |
3840d6ba | 951 | |
0542e38e | 952 | bytes = length; |
953 | ||
4a73831b | 954 | DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes)); |
955 | ||
0542e38e | 956 | memcpy(buffer, http->buffer, length); |
957 | http->used -= length; | |
958 | ||
959 | if (http->used > 0) | |
dfac1292 | 960 | memmove(http->buffer, http->buffer + length, http->used); |
50146867 | 961 | } |
bcf61448 | 962 | #ifdef HAVE_SSL |
a75c006a | 963 | else if (http->tls) |
92e48f04 | 964 | { |
965 | if (!http->blocking && !httpWait(http, 1000)) | |
966 | return (0); | |
bcf61448 | 967 | bytes = http_read_ssl(http, buffer, length); |
92e48f04 | 968 | } |
bcf61448 | 969 | #endif /* HAVE_SSL */ |
0542e38e | 970 | else |
4a73831b | 971 | { |
92e48f04 | 972 | if (!http->blocking && !httpWait(http, 1000)) |
973 | return (0); | |
4a73831b | 974 | DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length)); |
0542e38e | 975 | bytes = recv(http->fd, buffer, length, 0); |
4a73831b | 976 | DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes)); |
977 | } | |
3840d6ba | 978 | |
0542e38e | 979 | if (bytes > 0) |
980 | http->data_remaining -= bytes; | |
0bf5ae82 | 981 | else if (bytes < 0) |
bdbaa675 | 982 | { |
c3026ddc | 983 | #ifdef WIN32 |
977acbd3 | 984 | http->error = WSAGetLastError(); |
985 | #else | |
bdbaa675 | 986 | if (errno == EINTR) |
987 | bytes = 0; | |
988 | else | |
989 | http->error = errno; | |
c3026ddc | 990 | #endif /* WIN32 */ |
bdbaa675 | 991 | } |
92e48f04 | 992 | else if (bytes == 0) |
993 | { | |
994 | http->error = EPIPE; | |
995 | return 0; | |
996 | } | |
0542e38e | 997 | |
4355fb2f | 998 | if (http->data_remaining == 0) |
4a73831b | 999 | { |
5e879034 | 1000 | if (http->data_encoding == HTTP_ENCODE_CHUNKED) |
4355fb2f | 1001 | httpGets(len, sizeof(len), http); |
1002 | ||
1003 | if (http->data_encoding != HTTP_ENCODE_CHUNKED) | |
1004 | { | |
1005 | if (http->state == HTTP_POST_RECV) | |
1006 | http->state ++; | |
1007 | else | |
1008 | http->state = HTTP_WAITING; | |
1009 | } | |
4a73831b | 1010 | } |
1011 | ||
0f33610c | 1012 | #ifdef DEBUG |
1013 | { | |
1014 | int i, j, ch; | |
1015 | printf("httpRead: Read %d bytes:\n", bytes); | |
1016 | for (i = 0; i < bytes; i += 16) | |
1017 | { | |
1018 | printf(" "); | |
1019 | ||
1020 | for (j = 0; j < 16 && (i + j) < bytes; j ++) | |
1021 | printf(" %02X", buffer[i + j] & 255); | |
1022 | ||
1023 | while (j < 16) | |
1024 | { | |
1025 | printf(" "); | |
1026 | j ++; | |
1027 | } | |
1028 | ||
1029 | printf(" "); | |
1030 | for (j = 0; j < 16 && (i + j) < bytes; j ++) | |
1031 | { | |
1032 | ch = buffer[i + j] & 255; | |
1033 | ||
1034 | if (ch < ' ' || ch == 127) | |
1035 | ch = '.'; | |
1036 | ||
1037 | putchar(ch); | |
1038 | } | |
1039 | putchar('\n'); | |
1040 | } | |
1041 | } | |
1042 | #endif /* DEBUG */ | |
1043 | ||
0542e38e | 1044 | return (bytes); |
3840d6ba | 1045 | } |
1046 | ||
1047 | ||
d40085f1 | 1048 | /* |
1049 | * 'httpSetCookie()' - Set the cookie value(s)... | |
1050 | */ | |
1051 | ||
1052 | void | |
1053 | httpSetCookie(http_t *http, /* I - Connection */ | |
1054 | const char *cookie) /* I - Cookie string */ | |
1055 | { | |
1056 | if (!http) | |
1057 | return; | |
1058 | ||
1059 | if (http->cookie) | |
1060 | free(http->cookie); | |
1061 | ||
1062 | if (cookie) | |
1063 | http->cookie = strdup(cookie); | |
1064 | else | |
1065 | http->cookie = NULL; | |
1066 | } | |
1067 | ||
1068 | ||
2e32fcdb | 1069 | /* |
1070 | * 'httpWait()' - Wait for data available on a connection. | |
1071 | */ | |
1072 | ||
1073 | int /* O - 1 if data is available, 0 otherwise */ | |
1074 | httpWait(http_t *http, /* I - HTTP data */ | |
1075 | int msec) /* I - Milliseconds to wait */ | |
1076 | { | |
63d94476 | 1077 | #ifndef WIN32 |
2e32fcdb | 1078 | struct rlimit limit; /* Runtime limit */ |
63d94476 | 1079 | #endif /* !WIN32 */ |
2e32fcdb | 1080 | struct timeval timeout; /* Timeout */ |
63d94476 | 1081 | int nfds; /* Result from select() */ |
2e32fcdb | 1082 | |
1083 | ||
1084 | /* | |
1085 | * First see if there is data in the buffer... | |
1086 | */ | |
1087 | ||
1088 | if (http == NULL) | |
1089 | return (0); | |
1090 | ||
1091 | if (http->used) | |
1092 | return (1); | |
1093 | ||
1094 | /* | |
1095 | * Then try doing a select() to poll the socket... | |
1096 | */ | |
1097 | ||
1098 | if (!http->input_set) | |
1099 | { | |
63d94476 | 1100 | #ifdef WIN32 |
1101 | /* | |
1102 | * Windows has a fixed-size select() structure, different (surprise, | |
1103 | * surprise!) from all UNIX implementations. Just allocate this | |
1104 | * fixed structure... | |
1105 | */ | |
1106 | ||
1107 | http->input_set = calloc(1, sizeof(fd_set)); | |
1108 | #else | |
2e32fcdb | 1109 | /* |
1110 | * Allocate the select() input set based upon the max number of file | |
1111 | * descriptors available for this process... | |
1112 | */ | |
1113 | ||
1114 | getrlimit(RLIMIT_NOFILE, &limit); | |
1115 | ||
1116 | http->input_set = calloc(1, (limit.rlim_cur + 7) / 8); | |
63d94476 | 1117 | #endif /* WIN32 */ |
2e32fcdb | 1118 | |
1119 | if (!http->input_set) | |
1120 | return (0); | |
1121 | } | |
1122 | ||
1123 | FD_SET(http->fd, http->input_set); | |
1124 | ||
1125 | if (msec >= 0) | |
1126 | { | |
1127 | timeout.tv_sec = msec / 1000; | |
1128 | timeout.tv_usec = (msec % 1000) * 1000; | |
1129 | ||
63d94476 | 1130 | nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout); |
2e32fcdb | 1131 | } |
1132 | else | |
63d94476 | 1133 | nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL); |
1134 | ||
1135 | FD_CLR(http->fd, http->input_set); | |
1136 | ||
1137 | return (nfds > 0); | |
2e32fcdb | 1138 | } |
1139 | ||
1140 | ||
3840d6ba | 1141 | /* |
50146867 | 1142 | * 'httpWrite()' - Write data to a HTTP connection. |
3840d6ba | 1143 | */ |
50146867 | 1144 | |
1145 | int /* O - Number of bytes written */ | |
063e1ac7 | 1146 | httpWrite(http_t *http, /* I - HTTP data */ |
1147 | const char *buffer, /* I - Buffer for data */ | |
1148 | int length) /* I - Number of bytes to write */ | |
3840d6ba | 1149 | { |
977acbd3 | 1150 | int tbytes, /* Total bytes sent */ |
1151 | bytes; /* Bytes sent */ | |
3840d6ba | 1152 | |
1153 | ||
50146867 | 1154 | if (http == NULL || buffer == NULL) |
1155 | return (-1); | |
3840d6ba | 1156 | |
50146867 | 1157 | http->activity = time(NULL); |
1158 | ||
5e879034 | 1159 | if (http->data_encoding == HTTP_ENCODE_CHUNKED) |
8d5f8b3e | 1160 | { |
4355fb2f | 1161 | if (httpPrintf(http, "%x\r\n", length) < 0) |
50146867 | 1162 | return (-1); |
3840d6ba | 1163 | |
8d5f8b3e | 1164 | if (length == 0) |
1165 | { | |
1166 | /* | |
1167 | * A zero-length chunk ends a transfer; unless we are sending POST | |
1168 | * data, go idle... | |
1169 | */ | |
1170 | ||
1171 | DEBUG_puts("httpWrite: changing states..."); | |
1172 | ||
1173 | if (http->state == HTTP_POST_RECV) | |
1174 | http->state ++; | |
753453e4 | 1175 | else if (http->state == HTTP_PUT_RECV) |
1176 | http->state = HTTP_STATUS; | |
8d5f8b3e | 1177 | else |
1178 | http->state = HTTP_WAITING; | |
1179 | ||
1180 | if (httpPrintf(http, "\r\n") < 0) | |
1181 | return (-1); | |
1182 | ||
1183 | return (0); | |
1184 | } | |
1185 | } | |
1186 | ||
50146867 | 1187 | tbytes = 0; |
4a73831b | 1188 | |
50146867 | 1189 | while (length > 0) |
1190 | { | |
bcf61448 | 1191 | #ifdef HAVE_SSL |
a75c006a | 1192 | if (http->tls) |
bcf61448 | 1193 | bytes = http_write_ssl(http, buffer, length); |
a75c006a | 1194 | else |
bcf61448 | 1195 | #endif /* HAVE_SSL */ |
50146867 | 1196 | bytes = send(http->fd, buffer, length, 0); |
a75c006a | 1197 | |
50146867 | 1198 | if (bytes < 0) |
4a73831b | 1199 | { |
bdbaa675 | 1200 | #ifdef WIN32 |
1201 | if (WSAGetLastError() != http->error) | |
1202 | { | |
1203 | http->error = WSAGetLastError(); | |
1204 | continue; | |
1205 | } | |
1206 | #else | |
1207 | if (errno == EINTR) | |
1208 | continue; | |
1209 | else if (errno != http->error) | |
1210 | { | |
1211 | http->error = errno; | |
1212 | continue; | |
1213 | } | |
1214 | #endif /* WIN32 */ | |
1215 | ||
4a73831b | 1216 | DEBUG_puts("httpWrite: error writing data...\n"); |
c1918ec5 | 1217 | |
50146867 | 1218 | return (-1); |
4a73831b | 1219 | } |
3840d6ba | 1220 | |
50146867 | 1221 | buffer += bytes; |
1222 | tbytes += bytes; | |
1223 | length -= bytes; | |
69ee1496 | 1224 | if (http->data_encoding == HTTP_ENCODE_LENGTH) |
1225 | http->data_remaining -= bytes; | |
1226 | } | |
1227 | ||
5e879034 | 1228 | if (http->data_encoding == HTTP_ENCODE_CHUNKED) |
4355fb2f | 1229 | if (httpPrintf(http, "\r\n") < 0) |
1230 | return (-1); | |
1231 | ||
8d5f8b3e | 1232 | if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH) |
69ee1496 | 1233 | { |
1234 | /* | |
1235 | * Finished with the transfer; unless we are sending POST data, go idle... | |
1236 | */ | |
1237 | ||
8d5f8b3e | 1238 | DEBUG_puts("httpWrite: changing states..."); |
1239 | ||
69ee1496 | 1240 | if (http->state == HTTP_POST_RECV) |
1241 | http->state ++; | |
1242 | else | |
1243 | http->state = HTTP_WAITING; | |
50146867 | 1244 | } |
1245 | ||
0f33610c | 1246 | #ifdef DEBUG |
1247 | { | |
1248 | int i, j, ch; | |
1249 | printf("httpWrite: wrote %d bytes: \n", tbytes); | |
1250 | for (i = 0, buffer -= tbytes; i < tbytes; i += 16) | |
1251 | { | |
1252 | printf(" "); | |
1253 | ||
1254 | for (j = 0; j < 16 && (i + j) < tbytes; j ++) | |
1255 | printf(" %02X", buffer[i + j] & 255); | |
1256 | ||
1257 | while (j < 16) | |
1258 | { | |
1259 | printf(" "); | |
1260 | j ++; | |
1261 | } | |
4a73831b | 1262 | |
0f33610c | 1263 | printf(" "); |
1264 | for (j = 0; j < 16 && (i + j) < tbytes; j ++) | |
1265 | { | |
1266 | ch = buffer[i + j] & 255; | |
1267 | ||
1268 | if (ch < ' ' || ch == 127) | |
1269 | ch = '.'; | |
1270 | ||
1271 | putchar(ch); | |
1272 | } | |
1273 | putchar('\n'); | |
1274 | } | |
1275 | } | |
1276 | #endif /* DEBUG */ | |
50146867 | 1277 | return (tbytes); |
1278 | } | |
1279 | ||
1280 | ||
1281 | /* | |
1282 | * 'httpGets()' - Get a line of text from a HTTP connection. | |
1283 | */ | |
1284 | ||
1285 | char * /* O - Line or NULL */ | |
1286 | httpGets(char *line, /* I - Line to read into */ | |
1287 | int length, /* I - Max length of buffer */ | |
1288 | http_t *http) /* I - HTTP data */ | |
1289 | { | |
1290 | char *lineptr, /* Pointer into line */ | |
1291 | *bufptr, /* Pointer into input buffer */ | |
1292 | *bufend; /* Pointer to end of buffer */ | |
1293 | int bytes; /* Number of bytes read */ | |
1294 | ||
1295 | ||
0f33610c | 1296 | DEBUG_printf(("httpGets(%p, %d, %p)\n", line, length, http)); |
4a73831b | 1297 | |
50146867 | 1298 | if (http == NULL || line == NULL) |
1299 | return (NULL); | |
1300 | ||
1301 | /* | |
1302 | * Pre-scan the buffer and see if there is a newline in there... | |
1303 | */ | |
1304 | ||
c3026ddc | 1305 | #ifdef WIN32 |
977acbd3 | 1306 | WSASetLastError(0); |
1307 | #else | |
0bf5ae82 | 1308 | errno = 0; |
c3026ddc | 1309 | #endif /* WIN32 */ |
f5174332 | 1310 | |
0542e38e | 1311 | do |
50146867 | 1312 | { |
0542e38e | 1313 | bufptr = http->buffer; |
1314 | bufend = http->buffer + http->used; | |
50146867 | 1315 | |
0542e38e | 1316 | while (bufptr < bufend) |
1317 | if (*bufptr == 0x0a) | |
1318 | break; | |
1319 | else | |
1320 | bufptr ++; | |
50146867 | 1321 | |
27d555e8 | 1322 | if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER) |
50146867 | 1323 | { |
1324 | /* | |
0542e38e | 1325 | * No newline; see if there is more data to be read... |
50146867 | 1326 | */ |
1327 | ||
2e32fcdb | 1328 | if (!http->blocking && !httpWait(http, 1000)) |
1329 | return (NULL); | |
1330 | ||
bcf61448 | 1331 | #ifdef HAVE_SSL |
a75c006a | 1332 | if (http->tls) |
bcf61448 | 1333 | bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used); |
a75c006a | 1334 | else |
bcf61448 | 1335 | #endif /* HAVE_SSL */ |
a75c006a | 1336 | bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0); |
1337 | ||
1338 | if (bytes < 0) | |
0542e38e | 1339 | { |
1340 | /* | |
1341 | * Nope, can't get a line this time... | |
1342 | */ | |
1343 | ||
c3026ddc | 1344 | #ifdef WIN32 |
977acbd3 | 1345 | if (WSAGetLastError() != http->error) |
1346 | { | |
1347 | http->error = WSAGetLastError(); | |
1348 | continue; | |
1349 | } | |
1350 | ||
1351 | DEBUG_printf(("httpGets(): recv() error %d!\n", WSAGetLastError())); | |
1352 | #else | |
bdbaa675 | 1353 | if (errno == EINTR) |
1354 | continue; | |
1355 | else if (errno != http->error) | |
f5174332 | 1356 | { |
0bf5ae82 | 1357 | http->error = errno; |
c1918ec5 | 1358 | continue; |
f5174332 | 1359 | } |
c1918ec5 | 1360 | |
1361 | DEBUG_printf(("httpGets(): recv() error %d!\n", errno)); | |
c3026ddc | 1362 | #endif /* WIN32 */ |
c1918ec5 | 1363 | |
0542e38e | 1364 | return (NULL); |
1365 | } | |
f5174332 | 1366 | else if (bytes == 0) |
0bf5ae82 | 1367 | { |
0bf5ae82 | 1368 | http->error = EPIPE; |
1369 | ||
f5174332 | 1370 | return (NULL); |
0bf5ae82 | 1371 | } |
0542e38e | 1372 | |
f5174332 | 1373 | /* |
1374 | * Yup, update the amount used and the end pointer... | |
1375 | */ | |
1376 | ||
1377 | http->used += bytes; | |
1378 | bufend += bytes; | |
dfac1292 | 1379 | bufptr = bufend; |
50146867 | 1380 | } |
1381 | } | |
27d555e8 | 1382 | while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER); |
50146867 | 1383 | |
1384 | http->activity = time(NULL); | |
1385 | ||
1386 | /* | |
1387 | * Read a line from the buffer... | |
1388 | */ | |
1389 | ||
1390 | lineptr = line; | |
1391 | bufptr = http->buffer; | |
1392 | bytes = 0; | |
584886cb | 1393 | length --; |
50146867 | 1394 | |
1395 | while (bufptr < bufend && bytes < length) | |
1396 | { | |
1397 | bytes ++; | |
1398 | ||
1399 | if (*bufptr == 0x0a) | |
1400 | { | |
1401 | bufptr ++; | |
584886cb | 1402 | break; |
50146867 | 1403 | } |
1404 | else if (*bufptr == 0x0d) | |
1405 | bufptr ++; | |
1406 | else | |
1407 | *lineptr++ = *bufptr++; | |
1408 | } | |
1409 | ||
584886cb | 1410 | if (bytes > 0) |
1411 | { | |
1412 | *lineptr = '\0'; | |
1413 | ||
1414 | http->used -= bytes; | |
1415 | if (http->used > 0) | |
dfac1292 | 1416 | memmove(http->buffer, bufptr, http->used); |
584886cb | 1417 | |
1418 | DEBUG_printf(("httpGets(): Returning \"%s\"\n", line)); | |
1419 | return (line); | |
1420 | } | |
1421 | ||
c1918ec5 | 1422 | DEBUG_puts("httpGets(): No new line available!"); |
1423 | ||
50146867 | 1424 | return (NULL); |
1425 | } | |
1426 | ||
1427 | ||
1428 | /* | |
1429 | * 'httpPrintf()' - Print a formatted string to a HTTP connection. | |
1430 | */ | |
1431 | ||
1432 | int /* O - Number of bytes written */ | |
1433 | httpPrintf(http_t *http, /* I - HTTP data */ | |
1434 | const char *format, /* I - printf-style format string */ | |
1435 | ...) /* I - Additional args as needed */ | |
1436 | { | |
1118e338 | 1437 | int bytes, /* Number of bytes to write */ |
1438 | nbytes, /* Number of bytes written */ | |
1439 | tbytes; /* Number of bytes all together */ | |
1440 | char buf[HTTP_MAX_BUFFER], /* Buffer for formatted string */ | |
1441 | *bufptr; /* Pointer into buffer */ | |
50146867 | 1442 | va_list ap; /* Variable argument pointer */ |
1443 | ||
1444 | ||
1445 | va_start(ap, format); | |
04de52f8 | 1446 | bytes = vsnprintf(buf, sizeof(buf), format, ap); |
50146867 | 1447 | va_end(ap); |
1448 | ||
5356dc5a | 1449 | DEBUG_printf(("httpPrintf: %s", buf)); |
1450 | ||
1118e338 | 1451 | for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes) |
a75c006a | 1452 | { |
bcf61448 | 1453 | #ifdef HAVE_SSL |
a75c006a | 1454 | if (http->tls) |
bcf61448 | 1455 | nbytes = http_write_ssl(http, bufptr, bytes - tbytes); |
a75c006a | 1456 | else |
bcf61448 | 1457 | #endif /* HAVE_SSL */ |
a75c006a | 1458 | nbytes = send(http->fd, bufptr, bytes - tbytes, 0); |
1459 | ||
1460 | if (nbytes < 0) | |
bdbaa675 | 1461 | { |
1462 | nbytes = 0; | |
1463 | ||
1464 | #ifdef WIN32 | |
1465 | if (WSAGetLastError() != http->error) | |
1466 | { | |
1467 | http->error = WSAGetLastError(); | |
1468 | continue; | |
1469 | } | |
1470 | #else | |
1471 | if (errno == EINTR) | |
1472 | continue; | |
1473 | else if (errno != http->error) | |
1474 | { | |
1475 | http->error = errno; | |
1476 | continue; | |
1477 | } | |
1478 | #endif /* WIN32 */ | |
1479 | ||
1118e338 | 1480 | return (-1); |
bdbaa675 | 1481 | } |
a75c006a | 1482 | } |
1118e338 | 1483 | |
1484 | return (bytes); | |
50146867 | 1485 | } |
1486 | ||
1487 | ||
1488 | /* | |
1489 | * 'httpStatus()' - Return a short string describing a HTTP status code. | |
1490 | */ | |
1491 | ||
063e1ac7 | 1492 | const char * /* O - String or NULL */ |
50146867 | 1493 | httpStatus(http_status_t status) /* I - HTTP status code */ |
1494 | { | |
1495 | switch (status) | |
1496 | { | |
b38fb7fc | 1497 | case HTTP_CONTINUE : |
1498 | return ("Continue"); | |
1499 | case HTTP_SWITCHING_PROTOCOLS : | |
1500 | return ("Switching Protocols"); | |
50146867 | 1501 | case HTTP_OK : |
1502 | return ("OK"); | |
1503 | case HTTP_CREATED : | |
1504 | return ("Created"); | |
1505 | case HTTP_ACCEPTED : | |
1506 | return ("Accepted"); | |
1507 | case HTTP_NO_CONTENT : | |
1508 | return ("No Content"); | |
1509 | case HTTP_NOT_MODIFIED : | |
1510 | return ("Not Modified"); | |
1511 | case HTTP_BAD_REQUEST : | |
1512 | return ("Bad Request"); | |
1513 | case HTTP_UNAUTHORIZED : | |
1514 | return ("Unauthorized"); | |
1515 | case HTTP_FORBIDDEN : | |
1516 | return ("Forbidden"); | |
1517 | case HTTP_NOT_FOUND : | |
1518 | return ("Not Found"); | |
1519 | case HTTP_REQUEST_TOO_LARGE : | |
1520 | return ("Request Entity Too Large"); | |
1521 | case HTTP_URI_TOO_LONG : | |
1522 | return ("URI Too Long"); | |
b38fb7fc | 1523 | case HTTP_UPGRADE_REQUIRED : |
1524 | return ("Upgrade Required"); | |
50146867 | 1525 | case HTTP_NOT_IMPLEMENTED : |
1526 | return ("Not Implemented"); | |
1527 | case HTTP_NOT_SUPPORTED : | |
1528 | return ("Not Supported"); | |
1529 | default : | |
1530 | return ("Unknown"); | |
1531 | } | |
1532 | } | |
1533 | ||
1534 | ||
50146867 | 1535 | /* |
1536 | * 'httpGetDateString()' - Get a formatted date/time string from a time value. | |
1537 | */ | |
1538 | ||
063e1ac7 | 1539 | const char * /* O - Date/time string */ |
50146867 | 1540 | httpGetDateString(time_t t) /* I - UNIX time */ |
1541 | { | |
1542 | struct tm *tdate; | |
1543 | static char datetime[256]; | |
1544 | ||
1545 | ||
1546 | tdate = gmtime(&t); | |
a6988fb1 | 1547 | snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT", |
1548 | days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon], | |
1549 | tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec); | |
50146867 | 1550 | |
1551 | return (datetime); | |
1552 | } | |
1553 | ||
1554 | ||
1555 | /* | |
1556 | * 'httpGetDateTime()' - Get a time value from a formatted date/time string. | |
1557 | */ | |
1558 | ||
1559 | time_t /* O - UNIX time */ | |
063e1ac7 | 1560 | httpGetDateTime(const char *s) /* I - Date/time string */ |
50146867 | 1561 | { |
a8374e1e | 1562 | int i; /* Looping var */ |
1563 | struct tm tdate; /* Time/date structure */ | |
1564 | char mon[16]; /* Abbreviated month name */ | |
1565 | int day, year; /* Day of month and year */ | |
1566 | int hour, min, sec; /* Time */ | |
1567 | ||
1568 | ||
04d61d56 | 1569 | if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6) |
a8374e1e | 1570 | return (0); |
1571 | ||
1572 | for (i = 0; i < 12; i ++) | |
1573 | if (strcasecmp(mon, months[i]) == 0) | |
1574 | break; | |
1575 | ||
1576 | if (i >= 12) | |
1577 | return (0); | |
1578 | ||
1579 | tdate.tm_mon = i; | |
1580 | tdate.tm_mday = day; | |
1581 | tdate.tm_year = year - 1900; | |
1582 | tdate.tm_hour = hour; | |
1583 | tdate.tm_min = min; | |
1584 | tdate.tm_sec = sec; | |
1585 | tdate.tm_isdst = 0; | |
1586 | ||
1587 | return (mktime(&tdate)); | |
50146867 | 1588 | } |
1589 | ||
1590 | ||
1591 | /* | |
1592 | * 'httpUpdate()' - Update the current HTTP state for incoming data. | |
1593 | */ | |
1594 | ||
a8374e1e | 1595 | http_status_t /* O - HTTP status */ |
50146867 | 1596 | httpUpdate(http_t *http) /* I - HTTP data */ |
1597 | { | |
a8374e1e | 1598 | char line[1024], /* Line from connection... */ |
1599 | *value; /* Pointer to value on line */ | |
1600 | http_field_t field; /* Field index */ | |
50146867 | 1601 | int major, minor; /* HTTP version numbers */ |
50146867 | 1602 | http_status_t status; /* Authorization status */ |
50146867 | 1603 | |
50146867 | 1604 | |
0f33610c | 1605 | DEBUG_printf(("httpUpdate(%p)\n", http)); |
4a73831b | 1606 | |
a8374e1e | 1607 | /* |
1608 | * If we haven't issued any commands, then there is nothing to "update"... | |
1609 | */ | |
3840d6ba | 1610 | |
a8374e1e | 1611 | if (http->state == HTTP_WAITING) |
1612 | return (HTTP_CONTINUE); | |
3840d6ba | 1613 | |
1614 | /* | |
a8374e1e | 1615 | * Grab all of the lines we can from the connection... |
3840d6ba | 1616 | */ |
1617 | ||
a8374e1e | 1618 | while (httpGets(line, sizeof(line), http) != NULL) |
fd8b1cf8 | 1619 | { |
f4cafe91 | 1620 | DEBUG_puts(line); |
9ae9d67c | 1621 | |
a8374e1e | 1622 | if (line[0] == '\0') |
fd8b1cf8 | 1623 | { |
a8374e1e | 1624 | /* |
1625 | * Blank line means the start of the data section (if any). Return | |
1626 | * the result code, too... | |
11b9b0d7 | 1627 | * |
1628 | * If we get status 100 (HTTP_CONTINUE), then we *don't* change states. | |
1629 | * Instead, we just return HTTP_CONTINUE to the caller and keep on | |
1630 | * tryin'... | |
a8374e1e | 1631 | */ |
1632 | ||
11b9b0d7 | 1633 | if (http->status == HTTP_CONTINUE) |
1634 | return (http->status); | |
1635 | ||
bcf61448 | 1636 | #ifdef HAVE_SSL |
b38fb7fc | 1637 | if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls) |
a75c006a | 1638 | { |
bcf61448 | 1639 | if (http_setup_ssl(http) != 0) |
a75c006a | 1640 | { |
bcf61448 | 1641 | # ifdef WIN32 |
a75c006a | 1642 | closesocket(http->fd); |
bcf61448 | 1643 | # else |
a75c006a | 1644 | close(http->fd); |
bcf61448 | 1645 | # endif /* WIN32 */ |
a75c006a | 1646 | |
1647 | return (HTTP_ERROR); | |
1648 | } | |
1649 | ||
a75c006a | 1650 | return (HTTP_CONTINUE); |
1651 | } | |
1652 | else if (http->status == HTTP_UPGRADE_REQUIRED && | |
1653 | http->encryption != HTTP_ENCRYPT_NEVER) | |
2a0ef17a | 1654 | http->encryption = HTTP_ENCRYPT_REQUIRED; |
bcf61448 | 1655 | #endif /* HAVE_SSL */ |
a75c006a | 1656 | |
5356dc5a | 1657 | httpGetLength(http); |
0542e38e | 1658 | |
1659 | switch (http->state) | |
1660 | { | |
1661 | case HTTP_GET : | |
1662 | case HTTP_POST : | |
1663 | case HTTP_POST_RECV : | |
1664 | case HTTP_PUT : | |
1665 | http->state ++; | |
dd63ebe2 | 1666 | case HTTP_POST_SEND : |
0542e38e | 1667 | break; |
1668 | ||
1669 | default : | |
1670 | http->state = HTTP_WAITING; | |
1671 | break; | |
1672 | } | |
a8374e1e | 1673 | |
1674 | return (http->status); | |
fd8b1cf8 | 1675 | } |
a8374e1e | 1676 | else if (strncmp(line, "HTTP/", 5) == 0) |
fd8b1cf8 | 1677 | { |
1678 | /* | |
a8374e1e | 1679 | * Got the beginning of a response... |
fd8b1cf8 | 1680 | */ |
1681 | ||
d21a7597 | 1682 | if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, (int *)&status) != 3) |
a8374e1e | 1683 | return (HTTP_ERROR); |
1684 | ||
1685 | http->version = (http_version_t)(major * 100 + minor); | |
1686 | http->status = status; | |
fd8b1cf8 | 1687 | } |
a8374e1e | 1688 | else if ((value = strchr(line, ':')) != NULL) |
3840d6ba | 1689 | { |
a8374e1e | 1690 | /* |
1691 | * Got a value... | |
1692 | */ | |
3a193f5e | 1693 | |
a8374e1e | 1694 | *value++ = '\0'; |
1695 | while (isspace(*value)) | |
1696 | value ++; | |
1697 | ||
0d1f75a3 | 1698 | /* |
1699 | * Be tolerants of servers that send unknown attribute fields... | |
1700 | */ | |
1701 | ||
d40085f1 | 1702 | if (!strcasecmp(line, "expect")) |
1703 | { | |
1704 | /* | |
1705 | * "Expect: 100-continue" or similar... | |
1706 | */ | |
1707 | ||
1708 | http->expect = (http_status_t)atoi(value); | |
1709 | } | |
1710 | else if (!strcasecmp(line, "cookie")) | |
1711 | { | |
1712 | /* | |
1713 | * "Cookie: name=value[; name=value ...]" - replaces previous cookies... | |
1714 | */ | |
1715 | ||
1716 | httpSetCookie(http, value); | |
1717 | } | |
1718 | else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN) | |
f4cafe91 | 1719 | { |
4a73831b | 1720 | DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line)); |
0d1f75a3 | 1721 | continue; |
f4cafe91 | 1722 | } |
d40085f1 | 1723 | else |
1724 | httpSetField(http, field, value); | |
3840d6ba | 1725 | } |
a8374e1e | 1726 | else |
f44afac9 | 1727 | { |
1728 | http->status = HTTP_ERROR; | |
a8374e1e | 1729 | return (HTTP_ERROR); |
f44afac9 | 1730 | } |
fd8b1cf8 | 1731 | } |
3840d6ba | 1732 | |
4e8f6c6a | 1733 | /* |
1734 | * See if there was an error... | |
1735 | */ | |
1736 | ||
0bf5ae82 | 1737 | if (http->error) |
f44afac9 | 1738 | { |
1739 | http->status = HTTP_ERROR; | |
4e8f6c6a | 1740 | return (HTTP_ERROR); |
f44afac9 | 1741 | } |
4e8f6c6a | 1742 | |
3840d6ba | 1743 | /* |
a8374e1e | 1744 | * If we haven't already returned, then there is nothing new... |
3840d6ba | 1745 | */ |
1746 | ||
a8374e1e | 1747 | return (HTTP_CONTINUE); |
3840d6ba | 1748 | } |
1749 | ||
1750 | ||
3a193f5e | 1751 | /* |
50146867 | 1752 | * 'httpDecode64()' - Base64-decode a string. |
3840d6ba | 1753 | */ |
1754 | ||
50146867 | 1755 | char * /* O - Decoded string */ |
063e1ac7 | 1756 | httpDecode64(char *out, /* I - String to write to */ |
1757 | const char *in) /* I - String to read from */ | |
3840d6ba | 1758 | { |
50146867 | 1759 | int pos, /* Bit position */ |
1760 | base64; /* Value of this character */ | |
1761 | char *outptr; /* Output pointer */ | |
3840d6ba | 1762 | |
3840d6ba | 1763 | |
50146867 | 1764 | for (outptr = out, pos = 0; *in != '\0'; in ++) |
fd8b1cf8 | 1765 | { |
50146867 | 1766 | /* |
1767 | * Decode this character into a number from 0 to 63... | |
1768 | */ | |
f736c0e3 | 1769 | |
50146867 | 1770 | if (*in >= 'A' && *in <= 'Z') |
1771 | base64 = *in - 'A'; | |
1772 | else if (*in >= 'a' && *in <= 'z') | |
1773 | base64 = *in - 'a' + 26; | |
1774 | else if (*in >= '0' && *in <= '9') | |
1775 | base64 = *in - '0' + 52; | |
1776 | else if (*in == '+') | |
1777 | base64 = 62; | |
1778 | else if (*in == '/') | |
1779 | base64 = 63; | |
1780 | else if (*in == '=') | |
1781 | break; | |
1782 | else | |
1783 | continue; | |
3840d6ba | 1784 | |
50146867 | 1785 | /* |
1786 | * Store the result in the appropriate chars... | |
1787 | */ | |
992cf15a | 1788 | |
1789 | switch (pos) | |
1790 | { | |
1791 | case 0 : | |
50146867 | 1792 | *outptr = base64 << 2; |
1793 | pos ++; | |
992cf15a | 1794 | break; |
50146867 | 1795 | case 1 : |
1796 | *outptr++ |= (base64 >> 4) & 3; | |
1797 | *outptr = (base64 << 4) & 255; | |
1798 | pos ++; | |
1799 | break; | |
1800 | case 2 : | |
1801 | *outptr++ |= (base64 >> 2) & 15; | |
1802 | *outptr = (base64 << 6) & 255; | |
1803 | pos ++; | |
1804 | break; | |
1805 | case 3 : | |
1806 | *outptr++ |= base64; | |
1807 | pos = 0; | |
992cf15a | 1808 | break; |
992cf15a | 1809 | } |
1810 | } | |
1811 | ||
50146867 | 1812 | *outptr = '\0'; |
3840d6ba | 1813 | |
1814 | /* | |
50146867 | 1815 | * Return the decoded string... |
3840d6ba | 1816 | */ |
1817 | ||
50146867 | 1818 | return (out); |
3840d6ba | 1819 | } |
1820 | ||
1821 | ||
f736c0e3 | 1822 | /* |
50146867 | 1823 | * 'httpEncode64()' - Base64-encode a string. |
f736c0e3 | 1824 | */ |
1825 | ||
50146867 | 1826 | char * /* O - Encoded string */ |
063e1ac7 | 1827 | httpEncode64(char *out, /* I - String to write to */ |
1828 | const char *in) /* I - String to read from */ | |
f736c0e3 | 1829 | { |
50146867 | 1830 | char *outptr; /* Output pointer */ |
6db7190f | 1831 | static const char base64[] = /* Base64 characters... */ |
50146867 | 1832 | { |
1833 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
1834 | "abcdefghijklmnopqrstuvwxyz" | |
1835 | "0123456789" | |
1836 | "+/" | |
1837 | }; | |
f736c0e3 | 1838 | |
f736c0e3 | 1839 | |
50146867 | 1840 | for (outptr = out; *in != '\0'; in ++) |
f736c0e3 | 1841 | { |
1842 | /* | |
50146867 | 1843 | * Encode the up to 3 characters as 4 Base64 numbers... |
f736c0e3 | 1844 | */ |
1845 | ||
50146867 | 1846 | *outptr ++ = base64[in[0] >> 2]; |
1847 | *outptr ++ = base64[((in[0] << 4) | (in[1] >> 4)) & 63]; | |
f736c0e3 | 1848 | |
50146867 | 1849 | in ++; |
1850 | if (*in == '\0') | |
f0af4f8f | 1851 | { |
1852 | *outptr ++ = '='; | |
50146867 | 1853 | break; |
f0af4f8f | 1854 | } |
f736c0e3 | 1855 | |
50146867 | 1856 | *outptr ++ = base64[((in[0] << 2) | (in[1] >> 6)) & 63]; |
f736c0e3 | 1857 | |
50146867 | 1858 | in ++; |
1859 | if (*in == '\0') | |
1860 | break; | |
f736c0e3 | 1861 | |
50146867 | 1862 | *outptr ++ = base64[in[0] & 63]; |
f736c0e3 | 1863 | } |
f736c0e3 | 1864 | |
50146867 | 1865 | *outptr ++ = '='; |
1866 | *outptr = '\0'; | |
f736c0e3 | 1867 | |
50146867 | 1868 | /* |
1869 | * Return the encoded string... | |
1870 | */ | |
f736c0e3 | 1871 | |
50146867 | 1872 | return (out); |
f736c0e3 | 1873 | } |
1874 | ||
1875 | ||
3a193f5e | 1876 | /* |
4a73831b | 1877 | * 'httpGetLength()' - Get the amount of data remaining from the |
1878 | * content-length or transfer-encoding fields. | |
0542e38e | 1879 | */ |
1880 | ||
063e1ac7 | 1881 | int /* O - Content length */ |
4a73831b | 1882 | httpGetLength(http_t *http) /* I - HTTP data */ |
0542e38e | 1883 | { |
dd63ebe2 | 1884 | DEBUG_printf(("httpGetLength(%p), state = %d\n", http, http->state)); |
5e879034 | 1885 | |
0542e38e | 1886 | if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0) |
1887 | { | |
5e879034 | 1888 | DEBUG_puts("httpGetLength: chunked request!"); |
1889 | ||
0542e38e | 1890 | http->data_encoding = HTTP_ENCODE_CHUNKED; |
1891 | http->data_remaining = 0; | |
1892 | } | |
1893 | else | |
1894 | { | |
5e879034 | 1895 | http->data_encoding = HTTP_ENCODE_LENGTH; |
0542e38e | 1896 | |
1897 | /* | |
1898 | * The following is a hack for HTTP servers that don't send a | |
1899 | * content-length or transfer-encoding field... | |
1900 | * | |
1901 | * If there is no content-length then the connection must close | |
1902 | * after the transfer is complete... | |
1903 | */ | |
1904 | ||
1905 | if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0') | |
1906 | http->data_remaining = 2147483647; | |
1907 | else | |
1908 | http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]); | |
5e879034 | 1909 | |
1910 | DEBUG_printf(("httpGetLength: content_length = %d\n", http->data_remaining)); | |
0542e38e | 1911 | } |
4a73831b | 1912 | |
1913 | return (http->data_remaining); | |
1914 | } | |
1915 | ||
1916 | ||
1917 | /* | |
1918 | * 'http_field()' - Return the field index for a field name. | |
1919 | */ | |
1920 | ||
1921 | static http_field_t /* O - Field index */ | |
063e1ac7 | 1922 | http_field(const char *name) /* I - String name */ |
4a73831b | 1923 | { |
1924 | int i; /* Looping var */ | |
1925 | ||
1926 | ||
1927 | for (i = 0; i < HTTP_FIELD_MAX; i ++) | |
1928 | if (strcasecmp(name, http_fields[i]) == 0) | |
1929 | return ((http_field_t)i); | |
1930 | ||
1931 | return (HTTP_FIELD_UNKNOWN); | |
0542e38e | 1932 | } |
1933 | ||
1934 | ||
a8374e1e | 1935 | /* |
1936 | * 'http_send()' - Send a request with all fields and the trailing blank line. | |
1937 | */ | |
1938 | ||
1939 | static int /* O - 0 on success, non-zero on error */ | |
1940 | http_send(http_t *http, /* I - HTTP data */ | |
1941 | http_state_t request, /* I - Request code */ | |
063e1ac7 | 1942 | const char *uri) /* I - URI */ |
a8374e1e | 1943 | { |
1944 | int i; /* Looping var */ | |
1945 | char *ptr, /* Pointer in buffer */ | |
1946 | buf[1024]; /* Encoded URI buffer */ | |
6db7190f | 1947 | static const char * const codes[] = |
1948 | { /* Request code strings */ | |
a8374e1e | 1949 | NULL, |
1950 | "OPTIONS", | |
1951 | "GET", | |
1952 | NULL, | |
1953 | "HEAD", | |
1954 | "POST", | |
1955 | NULL, | |
1956 | NULL, | |
1957 | "PUT", | |
1958 | NULL, | |
1959 | "DELETE", | |
1960 | "TRACE", | |
1961 | "CLOSE" | |
1962 | }; | |
6db7190f | 1963 | static const char hex[] = "0123456789ABCDEF"; |
a8374e1e | 1964 | /* Hex digits */ |
1965 | ||
1966 | ||
1967 | if (http == NULL || uri == NULL) | |
1968 | return (-1); | |
1969 | ||
1970 | /* | |
1971 | * Encode the URI as needed... | |
1972 | */ | |
1973 | ||
d2e58bfa | 1974 | for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++) |
a8374e1e | 1975 | if (*uri <= ' ' || *uri >= 127) |
1976 | { | |
d2e58bfa | 1977 | if (ptr < (buf + sizeof(buf) - 1)) |
1978 | *ptr ++ = '%'; | |
1979 | if (ptr < (buf + sizeof(buf) - 1)) | |
1980 | *ptr ++ = hex[(*uri >> 4) & 15]; | |
1981 | if (ptr < (buf + sizeof(buf) - 1)) | |
1982 | *ptr ++ = hex[*uri & 15]; | |
a8374e1e | 1983 | } |
1984 | else | |
1985 | *ptr ++ = *uri; | |
1986 | ||
1987 | *ptr = '\0'; | |
1988 | ||
f44afac9 | 1989 | /* |
1990 | * See if we had an error the last time around; if so, reconnect... | |
1991 | */ | |
1992 | ||
1993 | if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST) | |
1994 | httpReconnect(http); | |
1995 | ||
a8374e1e | 1996 | /* |
1997 | * Send the request header... | |
1998 | */ | |
1999 | ||
2000 | http->state = request; | |
5356dc5a | 2001 | if (request == HTTP_POST || request == HTTP_PUT) |
2002 | http->state ++; | |
2003 | ||
c1918ec5 | 2004 | http->status = HTTP_CONTINUE; |
2005 | ||
bcf61448 | 2006 | #ifdef HAVE_SSL |
2a0ef17a | 2007 | if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) |
a75c006a | 2008 | { |
2009 | httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); | |
2010 | httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0"); | |
2011 | } | |
bcf61448 | 2012 | #endif /* HAVE_SSL */ |
a75c006a | 2013 | |
406971d9 | 2014 | if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) |
a8374e1e | 2015 | { |
f44afac9 | 2016 | http->status = HTTP_ERROR; |
2017 | return (-1); | |
a8374e1e | 2018 | } |
2019 | ||
2020 | for (i = 0; i < HTTP_FIELD_MAX; i ++) | |
2021 | if (http->fields[i][0] != '\0') | |
4a73831b | 2022 | { |
2023 | DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i])); | |
2024 | ||
406971d9 | 2025 | if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1) |
f44afac9 | 2026 | { |
2027 | http->status = HTTP_ERROR; | |
2028 | return (-1); | |
2029 | } | |
4a73831b | 2030 | } |
a8374e1e | 2031 | |
406971d9 | 2032 | if (httpPrintf(http, "\r\n") < 1) |
f44afac9 | 2033 | { |
2034 | http->status = HTTP_ERROR; | |
a8374e1e | 2035 | return (-1); |
f44afac9 | 2036 | } |
a8374e1e | 2037 | |
2038 | httpClearFields(http); | |
2039 | ||
a8374e1e | 2040 | return (0); |
2041 | } | |
2042 | ||
2043 | ||
bcf61448 | 2044 | #ifdef HAVE_SSL |
2a0ef17a | 2045 | /* |
2046 | * 'http_upgrade()' - Force upgrade to TLS encryption. | |
2047 | */ | |
2048 | ||
2049 | static int /* O - Status of connection */ | |
2050 | http_upgrade(http_t *http) /* I - HTTP data */ | |
2051 | { | |
1c6682dd | 2052 | int ret; /* Return value */ |
2053 | http_t myhttp; /* Local copy of HTTP data */ | |
2054 | ||
2a0ef17a | 2055 | |
1c6682dd | 2056 | DEBUG_printf(("http_upgrade(%p)\n", http)); |
2057 | ||
2058 | /* | |
2059 | * Copy the HTTP data to a local variable so we can do the OPTIONS | |
2060 | * request without interfering with the existing request data... | |
2061 | */ | |
2062 | ||
2063 | memcpy(&myhttp, http, sizeof(myhttp)); | |
2a0ef17a | 2064 | |
2065 | /* | |
2066 | * Send an OPTIONS request to the server, requiring SSL or TLS | |
2067 | * encryption on the link... | |
2068 | */ | |
2069 | ||
1c6682dd | 2070 | httpClearFields(&myhttp); |
2071 | httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade"); | |
2072 | httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0"); | |
2073 | ||
2074 | if ((ret = httpOptions(&myhttp, "*")) == 0) | |
2075 | { | |
2076 | /* | |
2077 | * Wait for the secure connection... | |
2078 | */ | |
2079 | ||
2080 | while (httpUpdate(&myhttp) == HTTP_CONTINUE); | |
2081 | } | |
2082 | ||
2083 | httpFlush(&myhttp); | |
2a0ef17a | 2084 | |
2085 | /* | |
1c6682dd | 2086 | * Copy the HTTP data back over, if any... |
2a0ef17a | 2087 | */ |
2088 | ||
1c6682dd | 2089 | http->fd = myhttp.fd; |
2090 | http->error = myhttp.error; | |
2091 | http->activity = myhttp.activity; | |
2092 | http->status = myhttp.status; | |
2093 | http->version = myhttp.version; | |
2094 | http->keep_alive = myhttp.keep_alive; | |
2095 | http->used = myhttp.used; | |
2a0ef17a | 2096 | |
1c6682dd | 2097 | if (http->used) |
2098 | memcpy(http->buffer, myhttp.buffer, http->used); | |
2099 | ||
2100 | http->auth_type = myhttp.auth_type; | |
2101 | http->nonce_count = myhttp.nonce_count; | |
2102 | ||
2103 | memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce)); | |
2a0ef17a | 2104 | |
1c6682dd | 2105 | http->tls = myhttp.tls; |
2106 | http->encryption = myhttp.encryption; | |
2107 | ||
2108 | /* | |
2109 | * See if we actually went secure... | |
2110 | */ | |
2111 | ||
2112 | if (!http->tls) | |
2a0ef17a | 2113 | { |
1c6682dd | 2114 | /* |
2115 | * Server does not support HTTP upgrade... | |
2116 | */ | |
2a0ef17a | 2117 | |
1c6682dd | 2118 | DEBUG_puts("Server does not support HTTP upgrade!"); |
2a0ef17a | 2119 | |
dcfcaeac | 2120 | # ifdef WIN32 |
2a0ef17a | 2121 | closesocket(http->fd); |
dcfcaeac | 2122 | # else |
2a0ef17a | 2123 | close(http->fd); |
dcfcaeac | 2124 | # endif |
2a0ef17a | 2125 | |
1c6682dd | 2126 | http->fd = -1; |
2127 | ||
2a0ef17a | 2128 | return (-1); |
2129 | } | |
1c6682dd | 2130 | else |
2131 | return (ret); | |
2a0ef17a | 2132 | } |
2a0ef17a | 2133 | |
2134 | ||
3840d6ba | 2135 | /* |
bcf61448 | 2136 | * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. |
2137 | */ | |
2138 | ||
2139 | static int /* O - Status of connection */ | |
2140 | http_setup_ssl(http_t *http) /* I - HTTP data */ | |
2141 | { | |
dcfcaeac | 2142 | # ifdef HAVE_LIBSSL |
bcf61448 | 2143 | SSL_CTX *context; /* Context for encryption */ |
2144 | SSL *conn; /* Connection for encryption */ | |
dcfcaeac | 2145 | # elif defined(HAVE_GNUTLS) |
bcf61448 | 2146 | http_tls_t *conn; /* TLS session object */ |
dcfcaeac | 2147 | gnutls_certificate_client_credentials *credentials; |
2148 | /* TLS credentials */ | |
2149 | # elif defined(HAVE_CDSASSL) | |
2150 | SSLContextRef conn; /* Context for encryption */ | |
2151 | OSStatus error; /* Error info */ | |
2152 | # endif /* HAVE_LIBSSL */ | |
bcf61448 | 2153 | |
bcf61448 | 2154 | |
dcfcaeac | 2155 | # ifdef HAVE_LIBSSL |
bcf61448 | 2156 | context = SSL_CTX_new(SSLv23_client_method()); |
2157 | conn = SSL_new(context); | |
2158 | ||
2159 | SSL_set_fd(conn, http->fd); | |
2160 | if (SSL_connect(conn) != 1) | |
2161 | { | |
2162 | SSL_CTX_free(context); | |
2163 | SSL_free(conn); | |
2164 | ||
dcfcaeac | 2165 | # ifdef WIN32 |
bcf61448 | 2166 | http->error = WSAGetLastError(); |
dcfcaeac | 2167 | # else |
bcf61448 | 2168 | http->error = errno; |
dcfcaeac | 2169 | # endif /* WIN32 */ |
bcf61448 | 2170 | http->status = HTTP_ERROR; |
2171 | ||
2172 | return (HTTP_ERROR); | |
2173 | } | |
2174 | ||
dcfcaeac | 2175 | # elif defined(HAVE_GNUTLS) |
bcf61448 | 2176 | conn = (http_tls_t *)malloc(sizeof(http_tls_t)); |
dcfcaeac | 2177 | |
bcf61448 | 2178 | if (conn == NULL) |
2179 | { | |
2180 | http->error = errno; | |
2181 | http->status = HTTP_ERROR; | |
2182 | ||
2183 | return (-1); | |
2184 | } | |
dcfcaeac | 2185 | |
bcf61448 | 2186 | credentials = (gnutls_certificate_client_credentials *) |
dcfcaeac | 2187 | malloc(sizeof(gnutls_certificate_client_credentials)); |
bcf61448 | 2188 | if (credentials == NULL) |
2189 | { | |
2190 | free(conn); | |
2191 | ||
2192 | http->error = errno; | |
2193 | http->status = HTTP_ERROR; | |
2194 | ||
2195 | return (-1); | |
2196 | } | |
2197 | ||
2198 | gnutls_certificate_allocate_credentials(credentials); | |
2199 | ||
2200 | gnutls_init(&(conn->session), GNUTLS_CLIENT); | |
2201 | gnutls_set_default_priority(conn->session); | |
2202 | gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials); | |
2203 | gnutls_transport_set_ptr(conn->session, http->fd); | |
2204 | ||
2205 | if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS) | |
2206 | { | |
2207 | http->error = errno; | |
2208 | http->status = HTTP_ERROR; | |
2209 | ||
2210 | return (-1); | |
2211 | } | |
2212 | ||
2213 | conn->credentials = credentials; | |
2214 | ||
dcfcaeac | 2215 | # elif defined(HAVE_CDSASSL) |
2216 | error = SSLNewContext(false, &conn); | |
2217 | ||
2218 | if (!error) | |
2219 | error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc); | |
2220 | ||
2221 | if (!error) | |
2222 | error = SSLSetConnection(conn, (SSLConnectionRef)http->fd); | |
2223 | ||
2224 | if (!error) | |
2225 | error = SSLSetAllowsExpiredCerts(conn, true); | |
2226 | ||
2227 | if (!error) | |
2228 | error = SSLSetAllowsAnyRoot(conn, true); | |
2229 | ||
2230 | if (!error) | |
2231 | error = SSLHandshake(conn); | |
2232 | ||
2233 | if (error != 0) | |
2234 | { | |
2235 | http->error = error; | |
2236 | http->status = HTTP_ERROR; | |
2237 | ||
2238 | SSLDisposeContext(conn); | |
2239 | ||
2240 | close(http->fd); | |
2241 | ||
2242 | return (-1); | |
2243 | } | |
2244 | # endif /* HAVE_CDSASSL */ | |
bcf61448 | 2245 | |
2246 | http->tls = conn; | |
2247 | return (0); | |
2248 | } | |
2249 | ||
2250 | ||
2251 | /* | |
2252 | * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection. | |
2253 | */ | |
2254 | ||
2255 | static void | |
2256 | http_shutdown_ssl(http_t *http) /* I - HTTP data */ | |
2257 | { | |
dcfcaeac | 2258 | # ifdef HAVE_LIBSSL |
bcf61448 | 2259 | SSL_CTX *context; /* Context for encryption */ |
2260 | SSL *conn; /* Connection for encryption */ | |
2261 | ||
dcfcaeac | 2262 | |
bcf61448 | 2263 | conn = (SSL *)(http->tls); |
2264 | context = SSL_get_SSL_CTX(conn); | |
2265 | ||
2266 | SSL_shutdown(conn); | |
2267 | SSL_CTX_free(context); | |
2268 | SSL_free(conn); | |
dcfcaeac | 2269 | |
2270 | # elif defined(HAVE_GNUTLS) | |
2271 | http_tls_t *conn; /* Encryption session */ | |
2272 | gnutls_certificate_client_credentials *credentials; | |
2273 | /* TLS credentials */ | |
2274 | ||
bcf61448 | 2275 | |
2276 | conn = (http_tls_t *)(http->tls); | |
2277 | credentials = (gnutls_certificate_client_credentials *)(conn->credentials); | |
2278 | ||
2279 | gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); | |
2280 | gnutls_deinit(conn->session); | |
2281 | gnutls_certificate_free_credentials(*credentials); | |
2282 | free(credentials); | |
2283 | free(conn); | |
dcfcaeac | 2284 | |
2285 | # elif defined(HAVE_CDSASSL) | |
2286 | SSLClose((SSLContextRef)http->tls); | |
2287 | SSLDisposeContext((SSLContextRef)http->tls); | |
2288 | # endif /* HAVE_LIBSSL */ | |
bcf61448 | 2289 | |
2290 | http->tls = NULL; | |
2291 | } | |
2292 | ||
2293 | ||
2294 | /* | |
2295 | * 'http_read_ssl()' - Read from a SSL/TLS connection. | |
2296 | */ | |
2297 | ||
2298 | static int /* O - Bytes read */ | |
2299 | http_read_ssl(http_t *http, /* I - HTTP data */ | |
2300 | char *buf, /* I - Buffer to store data */ | |
2301 | int len) /* I - Length of buffer */ | |
2302 | { | |
dcfcaeac | 2303 | # if defined(HAVE_LIBSSL) |
bcf61448 | 2304 | return (SSL_read((SSL *)(http->tls), buf, len)); |
dcfcaeac | 2305 | |
2306 | # elif defined(HAVE_GNUTLS) | |
bcf61448 | 2307 | return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len)); |
dcfcaeac | 2308 | |
2309 | # elif defined(HAVE_CDSASSL) | |
2310 | OSStatus error; /* Error info */ | |
2311 | size_t processed; /* Number of bytes processed */ | |
2312 | ||
2313 | ||
2314 | error = SSLRead((SSLContextRef)http->tls, buf, len, &processed); | |
2315 | ||
2316 | if (error == 0) | |
2317 | return (processed); | |
2318 | else | |
2319 | { | |
2320 | http->error = error; | |
2321 | ||
2322 | return (-1); | |
2323 | } | |
2324 | # endif /* HAVE_LIBSSL */ | |
bcf61448 | 2325 | } |
2326 | ||
2327 | ||
2328 | /* | |
2329 | * 'http_write_ssl()' - Write to a SSL/TLS connection. | |
2330 | */ | |
2331 | ||
2332 | static int /* O - Bytes written */ | |
2333 | http_write_ssl(http_t *http, /* I - HTTP data */ | |
2334 | const char *buf, /* I - Buffer holding data */ | |
2335 | int len) /* I - Length of buffer */ | |
2336 | { | |
dcfcaeac | 2337 | # if defined(HAVE_LIBSSL) |
bcf61448 | 2338 | return (SSL_write((SSL *)(http->tls), buf, len)); |
dcfcaeac | 2339 | |
2340 | # elif defined(HAVE_GNUTLS) | |
bcf61448 | 2341 | return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len)); |
dcfcaeac | 2342 | # elif defined(HAVE_CDSASSL) |
2343 | OSStatus error; /* Error info */ | |
2344 | size_t processed; /* Number of bytes processed */ | |
2345 | ||
2346 | ||
2347 | error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed); | |
2348 | ||
2349 | if (error == 0) | |
2350 | return (processed); | |
2351 | else | |
2352 | { | |
2353 | http->error = error; | |
2354 | return (-1); | |
2355 | } | |
2356 | # endif /* HAVE_LIBSSL */ | |
2357 | } | |
2358 | ||
2359 | ||
2360 | # if defined(HAVE_CDSASSL) | |
2361 | /* | |
2362 | * 'CDSAReadFunc()' - Read function for CDSA decryption code. | |
2363 | */ | |
2364 | ||
2365 | static OSStatus /* O - -1 on error, 0 on success */ | |
2366 | CDSAReadFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */ | |
2367 | void *data, /* I - Data buffer */ | |
2368 | size_t *dataLength) /* IO - Number of bytes */ | |
2369 | { | |
2370 | ssize_t bytes; /* Number of bytes read */ | |
2371 | ||
2372 | ||
2373 | bytes = recv((int)connection, data, *dataLength, 0); | |
2374 | if (bytes >= 0) | |
2375 | { | |
2376 | *dataLength = bytes; | |
2377 | return (0); | |
2378 | } | |
2379 | else | |
2380 | return (-1); | |
bcf61448 | 2381 | } |
2382 | ||
dcfcaeac | 2383 | |
2384 | /* | |
2385 | * 'CDSAWriteFunc()' - Write function for CDSA encryption code. | |
2386 | */ | |
2387 | ||
2388 | static OSStatus /* O - -1 on error, 0 on success */ | |
2389 | CDSAWriteFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */ | |
2390 | const void *data, /* I - Data buffer */ | |
2391 | size_t *dataLength) /* IO - Number of bytes */ | |
2392 | { | |
2393 | ssize_t bytes; | |
2394 | ||
2395 | ||
2396 | bytes = write((int)connection, data, *dataLength); | |
2397 | if (bytes >= 0) | |
2398 | { | |
2399 | *dataLength = bytes; | |
2400 | return (0); | |
2401 | } | |
2402 | else | |
2403 | return (-1); | |
2404 | } | |
2405 | # endif /* HAVE_CDSASSL */ | |
bcf61448 | 2406 | #endif /* HAVE_SSL */ |
2407 | ||
dcfcaeac | 2408 | |
bcf61448 | 2409 | /* |
92e48f04 | 2410 | * End of "$Id: http.c,v 1.82.2.32 2003/05/09 16:06:43 mike Exp $". |
3840d6ba | 2411 | */ |