Coverage Report

Created: 2024-02-11 06:23

/src/cups/cups/http.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// HTTP routines for CUPS.
3
//
4
// Copyright © 2022-2024 by OpenPrinting.
5
// Copyright © 2007-2021 by Apple Inc.
6
// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7
//
8
// This file contains Kerberos support code, copyright 2006 by
9
// Jelmer Vernooij.
10
//
11
// Licensed under Apache License v2.0.  See the file "LICENSE" for more
12
// information.
13
//
14
15
#include "cups-private.h"
16
#include <fcntl.h>
17
#include <math.h>
18
#ifdef _WIN32
19
#  include <tchar.h>
20
#else
21
#  include <poll.h>
22
#  include <signal.h>
23
#  include <sys/time.h>
24
#  include <sys/resource.h>
25
#endif // _WIN32
26
#include <zlib.h>
27
28
29
//
30
// Local functions...
31
//
32
33
static void   http_add_field(http_t *http, http_field_t field, const char *value, int append);
34
static void   http_content_coding_finish(http_t *http);
35
static void   http_content_coding_start(http_t *http, const char *value);
36
static http_t   *http_create(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, _http_mode_t mode);
37
#ifdef DEBUG
38
static void   http_debug_hex(const char *prefix, const char *buffer, int bytes);
39
#endif // DEBUG
40
static ssize_t    http_read(http_t *http, char *buffer, size_t length);
41
static ssize_t    http_read_buffered(http_t *http, char *buffer, size_t length);
42
static ssize_t    http_read_chunk(http_t *http, char *buffer, size_t length);
43
static bool   http_send(http_t *http, http_state_t request, const char *uri);
44
static ssize_t    http_write(http_t *http, const char *buffer, size_t length);
45
static ssize_t    http_write_chunk(http_t *http, const char *buffer, size_t length);
46
static off_t    http_set_length(http_t *http);
47
static void   http_set_timeout(int fd, double timeout);
48
static void   http_set_wait(http_t *http);
49
static bool   http_tls_upgrade(http_t *http);
50
51
52
//
53
// Local globals...
54
//
55
56
static const char * const http_fields[] =
57
      {
58
        "Accept-Language",
59
        "Accept-Ranges",
60
        "Authorization",
61
        "Connection",
62
        "Content-Encoding",
63
        "Content-Language",
64
        "Content-Length",
65
        "Content-Location",
66
        "Content-MD5",
67
        "Content-Range",
68
        "Content-Type",
69
        "Content-Version",
70
        "Date",
71
        "Host",
72
        "If-Modified-Since",
73
        "If-Unmodified-since",
74
        "Keep-Alive",
75
        "Last-Modified",
76
        "Link",
77
        "Location",
78
        "Range",
79
        "Referer",
80
        "Retry-After",
81
        "Transfer-Encoding",
82
        "Upgrade",
83
        "User-Agent",
84
        "WWW-Authenticate",
85
        "Accept-Encoding",
86
        "Allow",
87
        "Server",
88
        "Authentication-Info",
89
        "Access-Control-Allow-Credentials",
90
        "Access-Control-Allow-Headers",
91
        "Access-Control-Allow-Methods",
92
        "Access-Control-Allow-Origin",
93
        "Access-Control-Expose-Headers",
94
        "Access-Control-Max-Age",
95
        "Access-Control-Request-Headers",
96
        "Access-Control-Request-Method",
97
        "Optional-WWW-Authenticate",
98
        "Origin",
99
        "OSCORE",
100
        "Strict-Transport-Security"
101
      };
102
103
104
//
105
// 'httpAcceptConnection()' - Accept a new HTTP client connection.
106
//
107
// This function accepts a new HTTP client connection from the specified
108
// listening socket "fd".  The "blocking" argument specifies whether the new
109
// HTTP connection is blocking.
110
//
111
// @since CUPS 1.7/macOS 10.9@
112
//
113
114
http_t *        // O - HTTP connection or `NULL`
115
httpAcceptConnection(int fd,    // I - Listen socket file descriptor
116
                     int blocking)  // I - 1 if the connection should be blocking, 0 otherwise
117
0
{
118
0
  http_t    *http;    // HTTP connection
119
0
  http_addrlist_t addrlist; // Dummy address list
120
0
  socklen_t   addrlen;  // Length of address
121
0
  int     val;    // Socket option value
122
123
124
  // Range check input...
125
0
  if (fd < 0)
126
0
    return (NULL);
127
128
  // Create the client connection...
129
0
  memset(&addrlist, 0, sizeof(addrlist));
130
131
0
  if ((http = http_create(NULL, 0, &addrlist, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, blocking, _HTTP_MODE_SERVER)) == NULL)
132
0
    return (NULL);
133
134
  // Accept the client and get the remote address...
135
0
  addrlen = sizeof(http_addr_t);
136
137
0
  if ((http->fd = accept(fd, (struct sockaddr *)&(http->addrlist->addr), &addrlen)) < 0)
138
0
  {
139
0
    _cupsSetHTTPError(HTTP_STATUS_ERROR);
140
0
    httpClose(http);
141
142
0
    return (NULL);
143
0
  }
144
145
0
  http->hostaddr = &(http->addrlist->addr);
146
147
0
  if (httpAddrIsLocalhost(http->hostaddr))
148
0
    cupsCopyString(http->hostname, "localhost", sizeof(http->hostname));
149
0
  else
150
0
    httpAddrGetString(http->hostaddr, http->hostname, sizeof(http->hostname));
151
152
#ifdef SO_NOSIGPIPE
153
  // Disable SIGPIPE for this socket.
154
  val = 1;
155
  setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
156
#endif // SO_NOSIGPIPE
157
158
  // Using TCP_NODELAY improves responsiveness, especially on systems with a
159
  // slow loopback interface.  Since we write large buffers when sending print
160
  // files and requests, there shouldn't be any performance penalty for this...
161
0
  val = 1;
162
0
  setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
163
164
0
#ifdef FD_CLOEXEC
165
  // Close this socket when starting another process...
166
0
  fcntl(http->fd, F_SETFD, FD_CLOEXEC);
167
0
#endif // FD_CLOEXEC
168
169
0
  return (http);
170
0
}
171
172
173
//
174
// 'httpAddCredential()' - Allocates and adds a single credential to an array.
175
//
176
// @deprecated@ @exclude all@
177
//
178
179
int         // O - 0 on success, -1 on error
180
httpAddCredential(
181
    cups_array_t *credentials,    // I - Credentials array
182
    const void   *data,     // I - PEM-encoded X.509 data
183
    size_t       datalen)   // I - Length of data
184
0
{
185
0
  (void)credentials;
186
0
  (void)data;
187
0
  (void)datalen;
188
189
0
  return (-1);
190
0
}
191
192
193
//
194
// 'httpBlocking()' - Set blocking/non-blocking behavior on a connection.
195
//
196
// @deprecated@
197
//
198
199
void
200
httpBlocking(http_t *http,    // I - HTTP connection
201
             int    b)      // I - 1 = blocking, 0 = non-blocking
202
0
{
203
0
  httpSetBlocking(http, b != 0);
204
0
}
205
206
207
//
208
// 'httpCheck()' - Check to see if there is a pending response from the server.
209
//
210
// @deprecated@
211
//
212
213
int         // O - 0 = no data, 1 = data available
214
httpCheck(http_t *http)     // I - HTTP connection
215
0
{
216
0
  return (httpWait(http, 0));
217
0
}
218
219
220
//
221
// 'httpClearCookie()' - Clear the cookie value(s).
222
//
223
// @since CUPS 1.1.19/macOS 10.3@
224
//
225
226
void
227
httpClearCookie(http_t *http)   // I - HTTP connection
228
0
{
229
0
  if (!http)
230
0
    return;
231
232
0
  if (http->cookie)
233
0
  {
234
0
    free(http->cookie);
235
0
    http->cookie = NULL;
236
0
  }
237
0
}
238
239
240
//
241
// 'httpClearFields()' - Clear HTTP request/response fields.
242
//
243
244
void
245
httpClearFields(http_t *http)   // I - HTTP connection
246
0
{
247
0
  http_field_t  field;      // Current field
248
249
250
0
  DEBUG_printf("httpClearFields(http=%p)", (void *)http);
251
252
0
  if (http)
253
0
  {
254
0
    memset(http->_fields, 0, sizeof(http->_fields));
255
256
0
    for (field = HTTP_FIELD_ACCEPT_LANGUAGE; field < HTTP_FIELD_ACCEPT_ENCODING; field ++)
257
0
    {
258
0
      if (!http->fields[field])
259
0
        continue;
260
261
0
      if (http->fields[field] != http->_fields[field])
262
0
        free(http->fields[field]);
263
264
0
      http->fields[field] = NULL;
265
0
    }
266
267
0
    for (; field < HTTP_FIELD_MAX; field ++)
268
0
    {
269
0
      if (!http->fields[field])
270
0
        continue;
271
272
0
      free(http->fields[field]);
273
0
      http->fields[field] = NULL;
274
0
    }
275
276
0
    if (http->mode == _HTTP_MODE_CLIENT)
277
0
    {
278
0
      if (http->hostname[0] == '/')
279
0
  httpSetField(http, HTTP_FIELD_HOST, "localhost");
280
0
      else
281
0
  httpSetField(http, HTTP_FIELD_HOST, http->hostname);
282
0
    }
283
284
0
    http->expect = (http_status_t)0;
285
0
  }
286
0
}
287
288
289
//
290
// 'httpClose()' - Close a HTTP connection.
291
//
292
293
void
294
httpClose(http_t *http)     // I - HTTP connection
295
0
{
296
#ifdef HAVE_GSSAPI
297
  OM_uint32 minor_status;   // Minor status code
298
#endif // HAVE_GSSAPI
299
300
301
0
  DEBUG_printf("httpClose(http=%p)", (void *)http);
302
303
  //
304
  // Range check input...
305
  //
306
307
0
  if (!http)
308
0
    return;
309
310
  //
311
  // Close any open connection...
312
  //
313
314
0
  _httpDisconnect(http);
315
316
  //
317
  // Free memory used...
318
  //
319
320
0
  httpAddrFreeList(http->addrlist);
321
322
0
  if (http->cookie)
323
0
    free(http->cookie);
324
325
#ifdef HAVE_GSSAPI
326
  if (http->gssctx != GSS_C_NO_CONTEXT)
327
    gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER);
328
329
  if (http->gssname != GSS_C_NO_NAME)
330
    gss_release_name(&minor_status, &http->gssname);
331
#endif // HAVE_GSSAPI
332
333
#ifdef HAVE_AUTHORIZATION_H
334
  if (http->auth_ref)
335
    AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
336
#endif // HAVE_AUTHORIZATION_H
337
338
0
  httpClearFields(http);
339
340
0
  if (http->authstring && http->authstring != http->_authstring)
341
0
    free(http->authstring);
342
343
0
  free(http);
344
0
}
345
346
347
//
348
// 'httpCompareCredentials()' - Compare two sets of X.509 credentials.
349
//
350
// @deprecated@ @exclude all@
351
//
352
353
int         // O - 1 if they match, 0 if they do not
354
httpCompareCredentials(
355
    cups_array_t *cred1,    // I - First set of X.509 credentials
356
    cups_array_t *cred2)    // I - Second set of X.509 credentials
357
0
{
358
0
  (void)cred1;
359
0
  (void)cred2;
360
361
0
  return (0);
362
0
}
363
364
365
//
366
// 'httpConnect()' - Connect to a HTTP server.
367
//
368
// This function is deprecated - use @link httpConnect2@ instead.
369
//
370
// @deprecated@ @exclude all@
371
//
372
373
http_t *        // O - New HTTP connection
374
httpConnect(const char *host,   // I - Host to connect to
375
            int        port)    // I - Port number
376
0
{
377
0
  return (httpConnect2(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL));
378
0
}
379
380
381
//
382
// 'httpConnect2()' - Connect to a HTTP server.
383
//
384
// This function creates a connection to a HTTP server.  The "host" and "port"
385
// arguments specify a hostname or IP address and port number to use while the
386
// "addrlist" argument specifies a list of addresses to use or `NULL` to do a
387
// fresh lookup.  The "family" argument specifies the address family to use -
388
// `AF_UNSPEC` to try both IPv4 and IPv6, `AF_INET` for IPv4, or `AF_INET6` for
389
// IPv6.
390
//
391
// The "encryption" argument specifies whether to encrypt the connection and the
392
// "blocking" argument specifies whether to use blocking behavior when reading
393
// or writing data.
394
//
395
// The "msec" argument specifies how long to try to connect to the server or `0`
396
// to just create an unconnected `http_t` object.  The "cancel" argument
397
// specifies an integer variable that can be set to a non-zero value to cancel
398
// the connection process.
399
//
400
// @since CUPS 1.7/macOS 10.9@
401
//
402
403
http_t *        // O - New HTTP connection
404
httpConnect2(
405
    const char        *host,    // I - Host to connect to
406
    int               port,   // I - Port number
407
    http_addrlist_t   *addrlist,  // I - List of addresses or `NULL` to lookup
408
    int               family,   // I - Address family to use or `AF_UNSPEC` for any
409
    http_encryption_t encryption, // I - Type of encryption to use
410
    int               blocking,   // I - 1 for blocking connection, 0 for non-blocking
411
    int               msec,   // I - Connection timeout in milliseconds, 0 means don't connect
412
    int               *cancel)    // I - Pointer to "cancel" variable
413
0
{
414
0
  http_t  *http;      // New HTTP connection
415
416
417
0
  DEBUG_printf("httpConnect2(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, msec=%d, cancel=%p)", host, port, (void *)addrlist, family, encryption, blocking, msec, (void *)cancel);
418
419
  // Create the HTTP structure...
420
0
  if ((http = http_create(host, port, addrlist, family, encryption, blocking, _HTTP_MODE_CLIENT)) == NULL)
421
0
    return (NULL);
422
423
  // Optionally connect to the remote system...
424
0
  if (msec == 0 || !httpReconnect2(http, msec, cancel))
425
0
    return (http);
426
427
  // Could not connect to any known address - bail out!
428
0
  httpClose(http);
429
430
0
  return (NULL);
431
0
}
432
433
434
//
435
// 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
436
//
437
// This function is now deprecated. Please use the @link httpConnect2@ function
438
// instead.
439
//
440
// @deprecated@ @exclude all@
441
//
442
443
http_t *        // O - New HTTP connection
444
httpConnectEncrypt(
445
    const char        *host,    // I - Host to connect to
446
    int               port,   // I - Port number
447
    http_encryption_t encryption) // I - Type of encryption to use
448
0
{
449
0
  DEBUG_printf("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)", host, port, encryption);
450
451
0
  return (httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL));
452
0
}
453
454
455
//
456
// 'httpDelete()' - Send a DELETE request to the server.
457
//
458
// @deprecated@ @exclude all@
459
//
460
461
int         // O - Status of call (0 = success)
462
httpDelete(http_t     *http,    // I - HTTP connection
463
           const char *uri)   // I - URI to delete
464
0
{
465
0
  return (http_send(http, HTTP_STATE_DELETE, uri) ? 0 : -1);
466
0
}
467
468
469
//
470
// '_httpDisconnect()' - Disconnect a HTTP connection.
471
//
472
473
void
474
_httpDisconnect(http_t *http)   // I - HTTP connection
475
0
{
476
0
  if (http->tls)
477
0
    _httpTLSStop(http);
478
479
0
  httpAddrClose(NULL, http->fd);
480
481
0
  http->fd = -1;
482
0
}
483
484
485
//
486
// 'httpEncryption()' - Set the required encryption on the link.
487
//
488
// @deprecated@ @exclude all@
489
//
490
491
int         // O - -1 on error, 0 on success
492
httpEncryption(http_t            *http, // I - HTTP connection
493
               http_encryption_t e) // I - New encryption preference
494
0
{
495
0
  return (httpSetEncryption(http, e) ? 0 : -1);
496
0
}
497
498
499
//
500
// 'httpError()' - Get the last error on a connection.
501
//
502
// @deprecated@ @exclude all@
503
//
504
505
int         // O - Error code (errno) value
506
httpError(http_t *http)     // I - HTTP connection
507
0
{
508
0
  return (httpGetError(http));
509
0
}
510
511
512
//
513
// 'httpFieldValue()' - Return the HTTP field enumeration value for a field name.
514
//
515
516
http_field_t        // O - Field index
517
httpFieldValue(const char *name)  // I - String name
518
0
{
519
0
  int i;        // Looping var
520
521
522
0
  for (i = 0; i < HTTP_FIELD_MAX; i ++)
523
0
  {
524
0
    if (!_cups_strcasecmp(name, http_fields[i]))
525
0
      return ((http_field_t)i);
526
0
  }
527
528
0
  return (HTTP_FIELD_UNKNOWN);
529
0
}
530
531
532
//
533
// 'httpFlush()' - Flush data read from a HTTP connection.
534
//
535
536
void
537
httpFlush(http_t *http)     // I - HTTP connection
538
0
{
539
0
  char    buffer[8192];   // Junk buffer
540
0
  int   blocking;   // To block or not to block
541
0
  http_state_t  oldstate;   // Old state
542
543
544
0
  DEBUG_printf("httpFlush(http=%p), state=%s", (void *)http, httpStateString(http->state));
545
546
  // Nothing to do if we are in the "waiting" state...
547
0
  if (http->state == HTTP_STATE_WAITING)
548
0
    return;
549
550
  // Temporarily set non-blocking mode so we don't get stuck in httpRead()...
551
0
  blocking = http->blocking;
552
0
  http->blocking = 0;
553
554
  // Read any data we can...
555
0
  oldstate = http->state;
556
0
  while (httpRead2(http, buffer, sizeof(buffer)) > 0);
557
558
  // Restore blocking and reset the connection if we didn't get all of
559
  // the remaining data...
560
0
  http->blocking = blocking;
561
562
0
  if (http->state == oldstate && http->state != HTTP_STATE_WAITING &&
563
0
      http->fd >= 0)
564
0
  {
565
    // Didn't get the data back, so close the current connection.
566
0
    if (http->coding)
567
0
      http_content_coding_finish(http);
568
569
0
    DEBUG_puts("1httpFlush: Setting state to HTTP_STATE_WAITING and closing.");
570
571
0
    http->state = HTTP_STATE_WAITING;
572
573
0
    if (http->tls)
574
0
      _httpTLSStop(http);
575
576
0
    httpAddrClose(NULL, http->fd);
577
578
0
    http->fd = -1;
579
0
  }
580
0
}
581
582
583
//
584
// 'httpFlushWrite()' - Flush data written to a HTTP connection.
585
//
586
// @since CUPS 1.2/macOS 10.5@
587
//
588
589
int         // O - Bytes written or -1 on error
590
httpFlushWrite(http_t *http)    // I - HTTP connection
591
0
{
592
0
  ssize_t bytes;      // Bytes written
593
594
595
0
  DEBUG_printf("httpFlushWrite(http=%p) data_encoding=%d", (void *)http, http ? http->data_encoding : 100);
596
597
0
  if (!http || !http->wused)
598
0
  {
599
0
    DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." : "1httpFlushWrite: No connection.");
600
0
    return (0);
601
0
  }
602
603
0
  if (http->data_encoding == HTTP_ENCODING_CHUNKED)
604
0
    bytes = http_write_chunk(http, http->wbuffer, (size_t)http->wused);
605
0
  else
606
0
    bytes = http_write(http, http->wbuffer, (size_t)http->wused);
607
608
0
  http->wused = 0;
609
610
0
  DEBUG_printf("1httpFlushWrite: Returning %d, errno=%d.", (int)bytes, errno);
611
612
0
  return ((int)bytes);
613
0
}
614
615
616
//
617
// 'httpFreeCredentials()' - Free an array of credentials.
618
//
619
// @deprecated@ @exclude all@
620
//
621
622
void
623
httpFreeCredentials(
624
    cups_array_t *credentials)    // I - Array of credentials
625
0
{
626
0
  (void)credentials;
627
0
}
628
629
630
//
631
// 'httpGet()' - Send a GET request to the server.
632
//
633
// @deprecated@ @exclude all@
634
//
635
636
int         // O - Status of call (0 = success)
637
httpGet(http_t     *http,   // I - HTTP connection
638
        const char *uri)    // I - URI to get
639
0
{
640
0
  return (http_send(http, HTTP_STATE_GET, uri) ? 0 : -1);
641
0
}
642
643
644
//
645
// 'httpGetActivity()' - Get the most recent activity for a connection.
646
//
647
// The return value is the time in seconds of the last read or write.
648
//
649
// @since CUPS 2.0/OS 10.10@
650
//
651
652
time_t          // O - Time of last read or write
653
httpGetActivity(http_t *http)   // I - HTTP connection
654
0
{
655
0
  return (http ? http->activity : 0);
656
0
}
657
658
659
//
660
// 'httpGetAuthString()' - Get the current authorization string.
661
//
662
// The authorization string is set by @link cupsDoAuthentication@ and
663
// @link httpSetAuthString@.  Use @link httpGetAuthString@ to retrieve the
664
// string to use with @link httpSetField@ for the
665
// `HTTP_FIELD_AUTHORIZATION` value.
666
//
667
// @since CUPS 1.3/macOS 10.5@
668
//
669
670
char *          // O - Authorization string
671
httpGetAuthString(http_t *http)   // I - HTTP connection
672
0
{
673
0
  if (http)
674
0
    return (http->authstring);
675
0
  else
676
0
    return (NULL);
677
0
}
678
679
680
//
681
// 'httpGetBlocking()' - Get the blocking/non-blocking state of a connection.
682
//
683
// @since CUPS 1.2/macOS 10.5@
684
//
685
686
int         // O - 1 if blocking, 0 if non-blocking
687
httpGetBlocking(http_t *http)   // I - HTTP connection
688
0
{
689
0
  return (http ? http->blocking : 0);
690
0
}
691
692
693
//
694
// 'httpGetContentEncoding()' - Get a common content encoding, if any, between
695
//                              the client and server.
696
//
697
// This function uses the value of the Accepts-Encoding HTTP header and must be
698
// called after receiving a response from the server or a request from the
699
// client.  The value returned can be use in subsequent requests (for clients)
700
// or in the response (for servers) in order to compress the content stream.
701
//
702
// @since CUPS 1.7/macOS 10.9@
703
//
704
705
const char *        // O - Content-Coding value or `NULL` for the identity coding.
706
httpGetContentEncoding(http_t *http)  // I - HTTP connection
707
0
{
708
0
  if (http && http->fields[HTTP_FIELD_ACCEPT_ENCODING])
709
0
  {
710
0
    int   i;      // Looping var
711
0
    char  temp[HTTP_MAX_VALUE], // Copy of Accepts-Encoding value
712
0
    *start,     // Start of coding value
713
0
    *end;     // End of coding value
714
0
    double  qvalue;     // "qvalue" for coding
715
0
    struct lconv *loc = localeconv(); // Locale data
716
0
    static const char * const codings[] =
717
0
    {         // Supported content codings
718
0
      "deflate",
719
0
      "gzip",
720
0
      "x-deflate",
721
0
      "x-gzip"
722
0
    };
723
724
0
    cupsCopyString(temp, http->fields[HTTP_FIELD_ACCEPT_ENCODING], sizeof(temp));
725
726
0
    for (start = temp; *start; start = end)
727
0
    {
728
      // Find the end of the coding name...
729
0
      qvalue = 1.0;
730
0
      end    = start;
731
0
      while (*end && *end != ';' && *end != ',' && !isspace(*end & 255))
732
0
        end ++;
733
734
0
      if (*end == ';')
735
0
      {
736
        // Grab the qvalue as needed...
737
0
        if (!strncmp(end, ";q=", 3))
738
0
          qvalue = _cupsStrScand(end + 3, NULL, loc);
739
740
        // Skip past all attributes...
741
0
        *end++ = '\0';
742
0
        while (*end && *end != ',' && !isspace(*end & 255))
743
0
          end ++;
744
0
      }
745
0
      else if (*end)
746
0
      {
747
0
        *end++ = '\0';
748
0
      }
749
750
0
      while (*end && isspace(*end & 255))
751
0
  end ++;
752
753
      // Check value if it matches something we support...
754
0
      if (qvalue <= 0.0)
755
0
        continue;
756
757
0
      for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++)
758
0
      {
759
0
        if (!strcmp(start, codings[i]))
760
0
          return (codings[i]);
761
0
      }
762
0
    }
763
0
  }
764
765
0
  return (NULL);
766
0
}
767
768
769
//
770
// 'httpGetCookie()' - Get any cookie data from the response.
771
//
772
// @since CUPS 1.1.19/macOS 10.3@
773
//
774
775
const char *        // O - Cookie data or `NULL`
776
httpGetCookie(http_t *http)   // I - HTTP connection
777
0
{
778
0
  return (http ? http->cookie : NULL);
779
0
}
780
781
782
//
783
// 'httpGetEncryption()' - Get the current encryption mode of a connection.
784
//
785
// This function returns the encryption mode for the connection. Use the
786
// @link httpIsEncrypted@ function to determine whether a TLS session has
787
// been established.
788
//
789
// @since CUPS 2.0/macOS 10.10@
790
//
791
792
http_encryption_t     // O - Current encryption mode
793
httpGetEncryption(http_t *http)   // I - HTTP connection
794
0
{
795
0
  return (http ? http->encryption : HTTP_ENCRYPTION_IF_REQUESTED);
796
0
}
797
798
799
//
800
// 'httpGetError()' - Get the last error on a connection.
801
//
802
// @since CUPS 2.5@
803
//
804
805
int         // O - Error code (errno) value
806
httpGetError(http_t *http)    // I - HTTP connection
807
0
{
808
0
  if (http)
809
0
    return (http->error);
810
0
  else
811
0
    return (EINVAL);
812
0
}
813
814
815
//
816
// 'httpGetExpect()' - Get the value of the Expect header, if any.
817
//
818
// Returns `HTTP_STATUS_NONE` if there is no Expect header, otherwise
819
// returns the expected HTTP status code, typically `HTTP_STATUS_CONTINUE`.
820
//
821
// @since CUPS 1.7/macOS 10.9@
822
//
823
824
http_status_t       // O - Expect: status, if any
825
httpGetExpect(http_t *http)   // I - HTTP connection
826
0
{
827
0
  if (!http)
828
0
    return (HTTP_STATUS_ERROR);
829
0
  else
830
0
    return (http->expect);
831
0
}
832
833
834
//
835
// 'httpGetFd()' - Get the file descriptor associated with a connection.
836
//
837
// @since CUPS 1.2/macOS 10.5@
838
//
839
840
int         // O - File descriptor or -1 if none
841
httpGetFd(http_t *http)     // I - HTTP connection
842
0
{
843
0
  return (http ? http->fd : -1);
844
0
}
845
846
847
//
848
// 'httpGetField()' - Get a field value from a request/response.
849
//
850
851
const char *        // O - Field value
852
httpGetField(http_t       *http,  // I - HTTP connection
853
             http_field_t field)  // I - Field to get
854
0
{
855
0
  if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
856
0
    return (NULL);
857
0
  else if (http->fields[field])
858
0
    return (http->fields[field]);
859
0
  else
860
0
    return ("");
861
0
}
862
863
864
//
865
// 'httpGetKeepAlive()' - Get the current Keep-Alive state of the connection.
866
//
867
// @since CUPS 2.0/OS 10.10@
868
//
869
870
http_keepalive_t      // O - Keep-Alive state
871
httpGetKeepAlive(http_t *http)    // I - HTTP connection
872
0
{
873
0
  return (http ? http->keep_alive : HTTP_KEEPALIVE_OFF);
874
0
}
875
876
877
//
878
// 'httpGetLength()' - Get the amount of data remaining from the Content-Length or Transfer-Encoding fields.
879
//
880
// This function is deprecated and will not return lengths larger than
881
// 2^31 - 1; use @link httpGetLength2@ instead.
882
//
883
// @deprecated@ @exclude all@
884
//
885
886
int         // O - Content length
887
httpGetLength(http_t *http)   // I - HTTP connection
888
0
{
889
  // Get the read content length and return the 32-bit value.
890
0
  if (http)
891
0
  {
892
0
    httpGetLength2(http);
893
894
0
    return (http->_data_remaining);
895
0
  }
896
0
  else
897
0
  {
898
0
    return (-1);
899
0
  }
900
0
}
901
902
903
//
904
// 'httpGetLength2()' - Get the amount of data remaining from the Content-Length or Transfer-Encoding fields.
905
//
906
// This function returns the complete content length, even for
907
// content larger than 2^31 - 1.
908
//
909
// @since CUPS 1.2/macOS 10.5@
910
//
911
912
off_t         // O - Content length
913
httpGetLength2(http_t *http)    // I - HTTP connection
914
0
{
915
0
  off_t     remaining;  // Remaining length
916
917
918
0
  DEBUG_printf("2httpGetLength2(http=%p), state=%s", (void *)http, http ? httpStateString(http->state) : "NONE");
919
920
0
  if (!http)
921
0
    return (-1);
922
923
0
  if (http->fields[HTTP_FIELD_TRANSFER_ENCODING] && !_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"))
924
0
  {
925
0
    DEBUG_puts("4httpGetLength2: chunked request!");
926
0
    remaining = 0;
927
0
  }
928
0
  else
929
0
  {
930
    // The following is a hack for HTTP servers that don't send a
931
    // Content-Length or Transfer-Encoding field...
932
    //
933
    // If there is no Content-Length then the connection must close
934
    // after the transfer is complete...
935
0
    if (!http->fields[HTTP_FIELD_CONTENT_LENGTH] || !http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
936
0
    {
937
      // Default content length is 0 for errors and certain types of operations,
938
      // and 2^31-1 for other successful requests...
939
0
      if (http->status >= HTTP_STATUS_MULTIPLE_CHOICES || http->state == HTTP_STATE_OPTIONS || (http->state == HTTP_STATE_GET && http->mode == _HTTP_MODE_SERVER) || http->state == HTTP_STATE_HEAD || (http->state == HTTP_STATE_PUT && http->mode == _HTTP_MODE_CLIENT) || http->state == HTTP_STATE_DELETE || http->state == HTTP_STATE_TRACE || http->state == HTTP_STATE_CONNECT)
940
0
        remaining = 0;
941
0
      else
942
0
        remaining = 2147483647;
943
0
    }
944
0
    else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH], NULL, 10)) < 0)
945
0
    {
946
0
      remaining = -1;
947
0
    }
948
949
0
    DEBUG_printf("4httpGetLength2: content_length=" CUPS_LLFMT, CUPS_LLCAST remaining);
950
0
  }
951
952
0
  return (remaining);
953
0
}
954
955
956
//
957
// 'httpGetPending()' - Get the number of bytes that are buffered for writing.
958
//
959
// @since CUPS 2.0/OS 10.10@
960
//
961
962
size_t          // O - Number of bytes buffered
963
httpGetPending(http_t *http)    // I - HTTP connection
964
0
{
965
0
  return (http ? (size_t)http->wused : 0);
966
0
}
967
968
969
//
970
// 'httpGetReady()' - Get the number of bytes that can be read without blocking.
971
//
972
// @since CUPS 2.0/OS 10.10@
973
//
974
975
size_t          // O - Number of bytes available
976
httpGetReady(http_t *http)    // I - HTTP connection
977
0
{
978
0
  if (!http)
979
0
    return (0);
980
0
  else if (http->used > 0)
981
0
    return ((size_t)http->used);
982
0
  else if (http->tls)
983
0
    return (_httpTLSPending(http));
984
985
0
  return (0);
986
0
}
987
988
989
//
990
// 'httpGetRemaining()' - Get the number of remaining bytes in the message body or current chunk.
991
//
992
// The @link httpIsChunked@ function can be used to determine whether the
993
// message body is chunked or fixed-length.
994
//
995
// @since CUPS 2.0/OS 10.10@
996
//
997
998
size_t          // O - Remaining bytes
999
httpGetRemaining(http_t *http)    // I - HTTP connection
1000
0
{
1001
0
  return (http ? (size_t)http->data_remaining : 0);
1002
0
}
1003
1004
1005
//
1006
// 'httpGets()' - Get a line of text from a HTTP connection.
1007
//
1008
// @deprecated@ @exclude all@
1009
//
1010
1011
char *          // O - Line or `NULL`
1012
httpGets(char   *line,      // I - Line to read into
1013
         int    length,     // I - Max length of buffer
1014
   http_t *http)      // I - HTTP connection
1015
0
{
1016
0
  return (httpGets2(http, line, (size_t)length));
1017
0
}
1018
1019
1020
//
1021
// 'httpGets2()' - Get a line of text from a HTTP connection.
1022
//
1023
1024
char *          // O - Line or `NULL`
1025
httpGets2(http_t *http,     // I - HTTP connection
1026
          char   *line,     // I - Line to read into
1027
          size_t length)    // I - Max length of buffer
1028
0
{
1029
0
  char    *lineptr,   // Pointer into line
1030
0
    *lineend,   // End of line
1031
0
    *bufptr,    // Pointer into input buffer
1032
0
          *bufend;    // Pointer to end of buffer
1033
0
  ssize_t bytes;      // Number of bytes read
1034
0
  int   eol;      // End-of-line?
1035
1036
1037
0
  DEBUG_printf("2httpGets2(http=%p, line=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)line, CUPS_LLCAST length);
1038
1039
0
  if (!http || !line || length <= 1)
1040
0
    return (NULL);
1041
1042
  // Read a line from the buffer...
1043
0
  http->error = 0;
1044
0
  lineptr     = line;
1045
0
  lineend     = line + length - 1;
1046
0
  eol         = 0;
1047
1048
0
  while (lineptr < lineend)
1049
0
  {
1050
    // Pre-load the buffer as needed...
1051
#ifdef _WIN32
1052
    WSASetLastError(0);
1053
#else
1054
0
    errno = 0;
1055
0
#endif // _WIN32
1056
1057
0
    while (http->used == 0)
1058
0
    {
1059
      // No newline; see if there is more data to be read...
1060
0
      while (!_httpWait(http, http->wait_value, 1))
1061
0
      {
1062
0
  if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1063
0
    continue;
1064
1065
0
        DEBUG_puts("3httpGets2: Timed out!");
1066
#ifdef _WIN32
1067
        http->error = WSAETIMEDOUT;
1068
#else
1069
0
        http->error = ETIMEDOUT;
1070
0
#endif // _WIN32
1071
0
        return (NULL);
1072
0
      }
1073
1074
0
      bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used));
1075
1076
0
      DEBUG_printf("4httpGets2: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes);
1077
1078
0
      if (bytes < 0)
1079
0
      {
1080
        // Nope, can't get a line this time...
1081
#ifdef _WIN32
1082
        DEBUG_printf("3httpGets2: recv() error %d!", WSAGetLastError());
1083
1084
        if (WSAGetLastError() == WSAEINTR)
1085
        {
1086
    continue;
1087
  }
1088
  else if (WSAGetLastError() == WSAEWOULDBLOCK)
1089
  {
1090
    if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1091
      continue;
1092
1093
    http->error = WSAGetLastError();
1094
  }
1095
  else if (WSAGetLastError() != http->error)
1096
  {
1097
    http->error = WSAGetLastError();
1098
    continue;
1099
  }
1100
1101
#else
1102
0
        DEBUG_printf("3httpGets2: recv() error %d!", errno);
1103
1104
0
        if (errno == EINTR)
1105
0
  {
1106
0
    continue;
1107
0
  }
1108
0
  else if (errno == EWOULDBLOCK || errno == EAGAIN)
1109
0
  {
1110
0
    if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1111
0
      continue;
1112
0
    else if (!http->timeout_cb && errno == EAGAIN)
1113
0
      continue;
1114
1115
0
    http->error = errno;
1116
0
  }
1117
0
  else if (errno != http->error)
1118
0
  {
1119
0
    http->error = errno;
1120
0
    continue;
1121
0
  }
1122
0
#endif // _WIN32
1123
1124
0
        return (NULL);
1125
0
      }
1126
0
      else if (bytes == 0)
1127
0
      {
1128
0
  http->error = EPIPE;
1129
1130
0
        return (NULL);
1131
0
      }
1132
1133
      // Yup, update the amount used...
1134
0
      http->used += (int)bytes;
1135
0
    }
1136
1137
    // Now copy as much of the current line as possible...
1138
0
    for (bufptr = http->buffer, bufend = http->buffer + http->used; lineptr < lineend && bufptr < bufend;)
1139
0
    {
1140
0
      if (*bufptr == 0x0a)
1141
0
      {
1142
0
        eol = 1;
1143
0
  bufptr ++;
1144
0
  break;
1145
0
      }
1146
0
      else if (*bufptr == 0x0d)
1147
0
      {
1148
0
        bufptr ++;
1149
0
      }
1150
0
      else
1151
0
      {
1152
0
  *lineptr++ = *bufptr++;
1153
0
      }
1154
0
    }
1155
1156
0
    http->used -= (int)(bufptr - http->buffer);
1157
0
    if (http->used > 0)
1158
0
      memmove(http->buffer, bufptr, (size_t)http->used);
1159
1160
0
    if (eol)
1161
0
    {
1162
      // End of line...
1163
0
      http->activity = time(NULL);
1164
1165
0
      *lineptr = '\0';
1166
1167
0
      DEBUG_printf("3httpGets2: Returning \"%s\"", line);
1168
1169
0
      return (line);
1170
0
    }
1171
0
  }
1172
1173
0
  DEBUG_puts("3httpGets2: No new line available!");
1174
1175
0
  return (NULL);
1176
0
}
1177
1178
1179
//
1180
// 'httpGetState()' - Get the current state of the HTTP request.
1181
//
1182
1183
http_state_t        // O - HTTP state
1184
httpGetState(http_t *http)    // I - HTTP connection
1185
0
{
1186
0
  return (http ? http->state : HTTP_STATE_ERROR);
1187
0
}
1188
1189
1190
//
1191
// 'httpGetStatus()' - Get the status of the last HTTP request.
1192
//
1193
// @since CUPS 1.2/macOS 10.5@
1194
//
1195
1196
http_status_t       // O - HTTP status
1197
httpGetStatus(http_t *http)   // I - HTTP connection
1198
0
{
1199
0
  return (http ? http->status : HTTP_STATUS_ERROR);
1200
0
}
1201
1202
1203
//
1204
// 'httpGetSubField()' - Get a sub-field value.
1205
//
1206
// @deprecated@ @exclude all@
1207
//
1208
1209
char *          // O - Value or `NULL`
1210
httpGetSubField(http_t       *http, // I - HTTP connection
1211
                http_field_t field, // I - Field index
1212
                const char   *name, // I - Name of sub-field
1213
    char         *value)  // O - Value string
1214
0
{
1215
0
  return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE));
1216
0
}
1217
1218
1219
//
1220
// 'httpGetSubField2()' - Get a sub-field value.
1221
//
1222
// @since CUPS 1.2/macOS 10.5@
1223
//
1224
1225
char *          // O - Value or `NULL`
1226
httpGetSubField2(http_t       *http,  // I - HTTP connection
1227
                 http_field_t field,  // I - Field index
1228
                 const char   *name,  // I - Name of sub-field
1229
     char         *value, // O - Value string
1230
     int          valuelen) // I - Size of value buffer
1231
0
{
1232
0
  const char  *fptr;      // Pointer into field
1233
0
  char    temp[HTTP_MAX_VALUE], // Temporary buffer for name
1234
0
    *ptr,     // Pointer into string buffer
1235
0
    *end;     // End of value buffer
1236
1237
0
  DEBUG_printf("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)", (void *)http, field, name, (void *)value, valuelen);
1238
1239
0
  if (value)
1240
0
    *value = '\0';
1241
1242
0
  if (!http || !name || !value || valuelen < 2 || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !http->fields[field])
1243
0
    return (NULL);
1244
1245
0
  end = value + valuelen - 1;
1246
1247
0
  for (fptr = http->fields[field]; *fptr;)
1248
0
  {
1249
    // Skip leading whitespace...
1250
0
    while (_cups_isspace(*fptr))
1251
0
      fptr ++;
1252
1253
0
    if (*fptr == ',')
1254
0
    {
1255
0
      fptr ++;
1256
0
      continue;
1257
0
    }
1258
1259
    // Get the sub-field name...
1260
0
    for (ptr = temp; *fptr && *fptr != '=' && !_cups_isspace(*fptr) && ptr < (temp + sizeof(temp) - 1); *ptr++ = *fptr++)
1261
0
      ; // Copy sub-field name
1262
1263
0
    *ptr = '\0';
1264
1265
0
    DEBUG_printf("4httpGetSubField2: name=\"%s\"", temp);
1266
1267
    // Skip trailing chars up to the '='...
1268
0
    while (_cups_isspace(*fptr))
1269
0
      fptr ++;
1270
1271
0
    if (!*fptr)
1272
0
      break;
1273
1274
0
    if (*fptr != '=')
1275
0
      continue;
1276
1277
    // Skip = and leading whitespace...
1278
0
    fptr ++;
1279
1280
0
    while (_cups_isspace(*fptr))
1281
0
      fptr ++;
1282
1283
0
    if (*fptr == '\"')
1284
0
    {
1285
      // Read quoted string...
1286
0
      for (ptr = value, fptr ++; *fptr && *fptr != '\"' && ptr < end; *ptr++ = *fptr++)
1287
0
        ; // Copy quoted string
1288
1289
0
      *ptr = '\0';
1290
1291
0
      while (*fptr && *fptr != '\"')
1292
0
        fptr ++;
1293
1294
0
      if (*fptr)
1295
0
        fptr ++;
1296
0
    }
1297
0
    else
1298
0
    {
1299
      // Read unquoted string...
1300
0
      for (ptr = value; *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end; *ptr++ = *fptr++)
1301
0
        ; // Copy unquoted string
1302
1303
0
      *ptr = '\0';
1304
1305
0
      while (*fptr && !_cups_isspace(*fptr) && *fptr != ',')
1306
0
        fptr ++;
1307
0
    }
1308
1309
0
    DEBUG_printf("4httpGetSubField2: value=\"%s\"", value);
1310
1311
    // See if this is the one...
1312
0
    if (!strcmp(name, temp))
1313
0
    {
1314
0
      DEBUG_printf("3httpGetSubField2: Returning \"%s\"", value);
1315
0
      return (value);
1316
0
    }
1317
0
  }
1318
1319
0
  value[0] = '\0';
1320
1321
0
  DEBUG_puts("3httpGetSubField2: Returning NULL");
1322
1323
0
  return (NULL);
1324
0
}
1325
1326
1327
//
1328
// 'httpGetVersion()' - Get the HTTP version at the other end.
1329
//
1330
1331
http_version_t        // O - Version number
1332
httpGetVersion(http_t *http)    // I - HTTP connection
1333
0
{
1334
0
  return (http ? http->version : HTTP_VERSION_1_0);
1335
0
}
1336
1337
1338
//
1339
// 'httpHead()' - Send a HEAD request to the server.
1340
//
1341
// @deprecated@ @exclude all@
1342
//
1343
1344
int         // O - Status of call (0 = success)
1345
httpHead(http_t     *http,    // I - HTTP connection
1346
         const char *uri)   // I - URI for head
1347
0
{
1348
0
  DEBUG_printf("httpHead(http=%p, uri=\"%s\")", (void *)http, uri);
1349
0
  return (http_send(http, HTTP_STATE_HEAD, uri) ? 0 : -1);
1350
0
}
1351
1352
1353
//
1354
// 'httpInitialize()' - Initialize the HTTP interface library and set the
1355
//                      default HTTP proxy (if any).
1356
//
1357
1358
void
1359
httpInitialize(void)
1360
0
{
1361
0
  static int  initialized = 0;  // Have we been called before?
1362
#ifdef _WIN32
1363
  WSADATA winsockdata;    // WinSock data
1364
#endif // _WIN32
1365
1366
1367
0
  _cupsGlobalLock();
1368
0
  if (initialized)
1369
0
  {
1370
0
    _cupsGlobalUnlock();
1371
0
    return;
1372
0
  }
1373
1374
#ifdef _WIN32
1375
  WSAStartup(MAKEWORD(2,2), &winsockdata);
1376
1377
#elif !defined(SO_NOSIGPIPE)
1378
  // Ignore SIGPIPE signals...
1379
0
  struct sigaction  action;   // POSIX sigaction data
1380
1381
1382
0
  memset(&action, 0, sizeof(action));
1383
0
  action.sa_handler = SIG_IGN;
1384
0
  sigaction(SIGPIPE, &action, NULL);
1385
0
#endif // _WIN32
1386
1387
0
  _httpTLSInitialize();
1388
1389
0
  initialized = 1;
1390
0
  _cupsGlobalUnlock();
1391
0
}
1392
1393
1394
//
1395
// 'httpIsChunked()' - Report whether a message body is chunked.
1396
//
1397
// This function returns non-zero if the message body is composed of
1398
// variable-length chunks.
1399
//
1400
// @since CUPS 2.0/OS 10.10@
1401
//
1402
1403
int         // O - 1 if chunked, 0 if not
1404
httpIsChunked(http_t *http)   // I - HTTP connection
1405
0
{
1406
0
  return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0);
1407
0
}
1408
1409
1410
//
1411
// 'httpIsEncrypted()' - Report whether a connection is encrypted.
1412
//
1413
// This function returns non-zero if the connection is currently encrypted.
1414
//
1415
// @since CUPS 2.0/OS 10.10@
1416
//
1417
1418
int         // O - 1 if encrypted, 0 if not
1419
httpIsEncrypted(http_t *http)   // I - HTTP connection
1420
0
{
1421
0
  return (http ? http->tls != NULL : 0);
1422
0
}
1423
1424
1425
//
1426
// 'httpOptions()' - Send an OPTIONS request to the server.
1427
//
1428
// @deprecated@ @exclude all@
1429
//
1430
1431
int         // O - Status of call (0 = success)
1432
httpOptions(http_t     *http,   // I - HTTP connection
1433
            const char *uri)    // I - URI for options
1434
0
{
1435
0
  return (http_send(http, HTTP_STATE_OPTIONS, uri) ? 0 : -1);
1436
0
}
1437
1438
1439
//
1440
// 'httpPeek()' - Peek at data from a HTTP connection.
1441
//
1442
// This function copies available data from the given HTTP connection, reading
1443
// a buffer as needed.  The data is still available for reading using
1444
// @link httpRead2@.
1445
//
1446
// For non-blocking connections the usual timeouts apply.
1447
//
1448
// @since CUPS 1.7/macOS 10.9@
1449
//
1450
1451
ssize_t         // O - Number of bytes copied
1452
httpPeek(http_t *http,      // I - HTTP connection
1453
         char   *buffer,    // I - Buffer for data
1454
   size_t length)     // I - Maximum number of bytes
1455
0
{
1456
0
  ssize_t bytes;      // Bytes read
1457
0
  char    len[32];    // Length string
1458
1459
1460
0
  DEBUG_printf("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length);
1461
1462
0
  if (http == NULL || buffer == NULL)
1463
0
    return (-1);
1464
1465
0
  http->activity = time(NULL);
1466
0
  http->error    = 0;
1467
1468
0
  if (length <= 0)
1469
0
    return (0);
1470
1471
0
  if (http->data_encoding == HTTP_ENCODING_CHUNKED && http->data_remaining <= 0)
1472
0
  {
1473
0
    DEBUG_puts("2httpPeek: Getting chunk length...");
1474
1475
0
    if (httpGets2(http, len, sizeof(len)) == NULL)
1476
0
    {
1477
0
      DEBUG_puts("1httpPeek: Could not get length!");
1478
0
      return (0);
1479
0
    }
1480
1481
0
    if (!len[0])
1482
0
    {
1483
0
      DEBUG_puts("1httpPeek: Blank chunk length, trying again...");
1484
0
      if (!httpGets2(http, len, sizeof(len)))
1485
0
      {
1486
0
  DEBUG_puts("1httpPeek: Could not get chunk length.");
1487
0
  return (0);
1488
0
      }
1489
0
    }
1490
1491
0
    http->data_remaining = strtoll(len, NULL, 16);
1492
1493
0
    if (http->data_remaining < 0)
1494
0
    {
1495
0
      DEBUG_puts("1httpPeek: Negative chunk length!");
1496
0
      return (0);
1497
0
    }
1498
0
  }
1499
1500
0
  DEBUG_printf("2httpPeek: data_remaining=" CUPS_LLFMT, CUPS_LLCAST http->data_remaining);
1501
1502
0
  if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS)
1503
0
  {
1504
    // A zero-length chunk ends a transfer; unless we are reading POST
1505
    // data, go idle...
1506
0
    if (http->coding >= _HTTP_CODING_GUNZIP)
1507
0
      http_content_coding_finish(http);
1508
1509
0
    if (http->data_encoding == HTTP_ENCODING_CHUNKED)
1510
0
      httpGets2(http, len, sizeof(len));
1511
1512
0
    if (http->state == HTTP_STATE_POST_RECV)
1513
0
      http->state ++;
1514
0
    else
1515
0
      http->state = HTTP_STATE_STATUS;
1516
1517
0
    DEBUG_printf("1httpPeek: 0-length chunk, set state to %s.", httpStateString(http->state));
1518
1519
    // Prevent future reads for this request...
1520
0
    http->data_encoding = HTTP_ENCODING_FIELDS;
1521
1522
0
    return (0);
1523
0
  }
1524
0
  else if (length > (size_t)http->data_remaining)
1525
0
  {
1526
0
    length = (size_t)http->data_remaining;
1527
0
  }
1528
1529
0
  if (http->used == 0 && (http->coding == _HTTP_CODING_IDENTITY || (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)))
1530
0
  {
1531
    // Buffer small reads for better performance...
1532
0
    ssize_t buflen;     // Length of read for buffer
1533
1534
0
    if (!http->blocking)
1535
0
    {
1536
0
      while (!httpWait(http, http->wait_value))
1537
0
      {
1538
0
  if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1539
0
    continue;
1540
1541
0
  return (0);
1542
0
      }
1543
0
    }
1544
1545
0
    if ((size_t)http->data_remaining > sizeof(http->buffer))
1546
0
      buflen = sizeof(http->buffer);
1547
0
    else
1548
0
      buflen = (ssize_t)http->data_remaining;
1549
1550
0
    DEBUG_printf("2httpPeek: Reading %d bytes into buffer.", (int)buflen);
1551
0
    bytes = http_read(http, http->buffer, (size_t)buflen);
1552
1553
0
    DEBUG_printf("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.", CUPS_LLCAST bytes);
1554
0
    if (bytes > 0)
1555
0
    {
1556
#ifdef DEBUG
1557
      http_debug_hex("httpPeek", http->buffer, (int)bytes);
1558
#endif // DEBUG
1559
1560
0
      http->used = (int)bytes;
1561
0
    }
1562
0
  }
1563
1564
0
  if (http->coding >= _HTTP_CODING_GUNZIP)
1565
0
  {
1566
0
    int   zerr;     // Decompressor error
1567
0
    z_stream  stream;     // Copy of decompressor stream
1568
1569
0
    if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER)
1570
0
    {
1571
0
      size_t buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in;
1572
          // Number of bytes to copy
1573
1574
0
      if (((z_stream *)http->stream)->avail_in > 0 && ((z_stream *)http->stream)->next_in > http->sbuffer)
1575
0
        memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
1576
1577
0
      ((z_stream *)http->stream)->next_in = http->sbuffer;
1578
1579
0
      if (buflen > (size_t)http->data_remaining)
1580
0
        buflen = (size_t)http->data_remaining;
1581
1582
0
      if (buflen > (size_t)http->used)
1583
0
        buflen = (size_t)http->used;
1584
1585
0
      DEBUG_printf("1httpPeek: Copying %d more bytes of data into decompression buffer.", (int)buflen);
1586
1587
0
      memcpy(http->sbuffer + ((z_stream *)http->stream)->avail_in, http->buffer, buflen);
1588
0
      ((z_stream *)http->stream)->avail_in += buflen;
1589
0
      http->used            -= (int)buflen;
1590
0
      http->data_remaining  -= (off_t)buflen;
1591
1592
0
      if (http->used > 0)
1593
0
        memmove(http->buffer, http->buffer + buflen, (size_t)http->used);
1594
0
    }
1595
1596
0
    DEBUG_printf("2httpPeek: length=%d, avail_in=%d", (int)length, (int)((z_stream *)http->stream)->avail_in);
1597
1598
0
    if (inflateCopy(&stream, (z_stream *)http->stream) != Z_OK)
1599
0
    {
1600
0
      DEBUG_puts("2httpPeek: Unable to copy decompressor stream.");
1601
0
      http->error = ENOMEM;
1602
0
      return (-1);
1603
0
    }
1604
1605
0
    stream.next_out  = (Bytef *)buffer;
1606
0
    stream.avail_out = (uInt)length;
1607
1608
0
    zerr = inflate(&stream, Z_SYNC_FLUSH);
1609
0
    inflateEnd(&stream);
1610
1611
0
    if (zerr < Z_OK)
1612
0
    {
1613
0
      DEBUG_printf("2httpPeek: zerr=%d", zerr);
1614
#ifdef DEBUG
1615
      http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
1616
#endif // DEBUG
1617
1618
0
      http->error = EIO;
1619
0
      return (-1);
1620
0
    }
1621
1622
0
    bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
1623
0
  }
1624
0
  else if (http->used > 0)
1625
0
  {
1626
0
    if (length > (size_t)http->used)
1627
0
      length = (size_t)http->used;
1628
1629
0
    bytes = (ssize_t)length;
1630
1631
0
    DEBUG_printf("2httpPeek: grabbing %d bytes from input buffer...", (int)bytes);
1632
1633
0
    memcpy(buffer, http->buffer, length);
1634
0
  }
1635
0
  else
1636
0
  {
1637
0
    bytes = 0;
1638
0
  }
1639
1640
0
  if (bytes < 0)
1641
0
  {
1642
#ifdef _WIN32
1643
    if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
1644
      bytes = 0;
1645
    else
1646
      http->error = WSAGetLastError();
1647
#else
1648
0
    if (errno == EINTR || errno == EAGAIN)
1649
0
      bytes = 0;
1650
0
    else
1651
0
      http->error = errno;
1652
0
#endif // _WIN32
1653
0
  }
1654
0
  else if (bytes == 0)
1655
0
  {
1656
0
    http->error = EPIPE;
1657
0
    return (0);
1658
0
  }
1659
1660
0
  return (bytes);
1661
0
}
1662
1663
1664
//
1665
// 'httpPost()' - Send a POST request to the server.
1666
//
1667
// @deprecated@ @exclude all@
1668
//
1669
1670
int         // O - Status of call (0 = success)
1671
httpPost(http_t     *http,    // I - HTTP connection
1672
         const char *uri)   // I - URI for post
1673
0
{
1674
0
  return (http_send(http, HTTP_STATE_POST, uri) ? 0 : -1);
1675
0
}
1676
1677
1678
//
1679
// 'httpPrintf()' - Print a formatted string to a HTTP connection.
1680
//
1681
// @private@
1682
//
1683
1684
int         // O - Number of bytes written or `-1` on error
1685
httpPrintf(http_t     *http,    // I - HTTP connection
1686
           const char *format,    // I - printf-style format string
1687
     ...)       // I - Additional args as needed
1688
0
{
1689
0
  ssize_t bytes;      // Number of bytes to write
1690
0
  char    buf[65536];   // Buffer for formatted string
1691
0
  va_list ap;     // Variable argument pointer
1692
1693
1694
0
  DEBUG_printf("2httpPrintf(http=%p, format=\"%s\", ...)", (void *)http, format);
1695
1696
0
  va_start(ap, format);
1697
0
  bytes = vsnprintf(buf, sizeof(buf), format, ap);
1698
0
  va_end(ap);
1699
1700
0
  DEBUG_printf("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf);
1701
1702
0
  if (bytes > (ssize_t)(sizeof(buf) - 1))
1703
0
  {
1704
0
    http->error = ENOMEM;
1705
0
    return (-1);
1706
0
  }
1707
0
  else if (http->data_encoding == HTTP_ENCODING_FIELDS)
1708
0
  {
1709
0
    return ((int)httpWrite2(http, buf, (size_t)bytes));
1710
0
  }
1711
0
  else
1712
0
  {
1713
0
    if (http->wused)
1714
0
    {
1715
0
      DEBUG_puts("4httpPrintf: flushing existing data...");
1716
1717
0
      if (httpFlushWrite(http) < 0)
1718
0
  return (-1);
1719
0
    }
1720
1721
0
    return ((int)http_write(http, buf, (size_t)bytes));
1722
0
  }
1723
0
}
1724
1725
1726
//
1727
// 'httpPut()' - Send a PUT request to the server.
1728
//
1729
// @deprecated@ @exclude all@
1730
//
1731
1732
int         // O - Status of call (0 = success)
1733
httpPut(http_t     *http,   // I - HTTP connection
1734
        const char *uri)    // I - URI to put
1735
0
{
1736
0
  DEBUG_printf("httpPut(http=%p, uri=\"%s\")", (void *)http, uri);
1737
0
  return (http_send(http, HTTP_STATE_PUT, uri) ? 0 : -1);
1738
0
}
1739
1740
1741
//
1742
// 'httpRead()' - Read data from a HTTP connection.
1743
//
1744
// This function is deprecated. Use the httpRead2() function which can
1745
// read more than 2GB of data.
1746
//
1747
// @deprecated@ @exclude all@
1748
//
1749
1750
int         // O - Number of bytes read
1751
httpRead(http_t *http,      // I - HTTP connection
1752
         char   *buffer,    // I - Buffer for data
1753
   int    length)     // I - Maximum number of bytes
1754
0
{
1755
0
  return ((int)httpRead2(http, buffer, (size_t)length));
1756
0
}
1757
1758
1759
//
1760
// 'httpRead2()' - Read data from a HTTP connection.
1761
//
1762
// @since CUPS 1.2/macOS 10.5@
1763
//
1764
1765
ssize_t         // O - Number of bytes read
1766
httpRead2(http_t *http,     // I - HTTP connection
1767
          char   *buffer,   // I - Buffer for data
1768
    size_t length)    // I - Maximum number of bytes
1769
0
{
1770
0
  ssize_t bytes;      // Bytes read
1771
1772
1773
0
  DEBUG_printf("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") coding=%d data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http ? http->coding : 0, http ? http->data_encoding : 0, CUPS_LLCAST (http ? http->data_remaining : -1));
1774
1775
0
  if (http == NULL || buffer == NULL)
1776
0
    return (-1);
1777
1778
0
  http->activity = time(NULL);
1779
0
  http->error    = 0;
1780
1781
0
  if (length <= 0)
1782
0
    return (0);
1783
1784
0
  if (http->coding >= _HTTP_CODING_GUNZIP)
1785
0
  {
1786
0
    do
1787
0
    {
1788
0
      if (((z_stream *)http->stream)->avail_in > 0)
1789
0
      {
1790
0
  int zerr;     // Decompressor error
1791
1792
0
  DEBUG_printf("2httpRead2: avail_in=%d, avail_out=%d", (int)((z_stream *)http->stream)->avail_in, (int)length);
1793
1794
0
  ((z_stream *)http->stream)->next_out  = (Bytef *)buffer;
1795
0
  ((z_stream *)http->stream)->avail_out = (uInt)length;
1796
1797
0
  if ((zerr = inflate((z_stream *)http->stream, Z_SYNC_FLUSH)) < Z_OK)
1798
0
  {
1799
0
    DEBUG_printf("2httpRead2: zerr=%d", zerr);
1800
#ifdef DEBUG
1801
          http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
1802
#endif // DEBUG
1803
1804
0
    http->error = EIO;
1805
0
    return (-1);
1806
0
  }
1807
1808
0
  bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
1809
1810
0
  DEBUG_printf("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d", ((z_stream *)http->stream)->avail_in, ((z_stream *)http->stream)->avail_out, (int)bytes);
1811
0
      }
1812
0
      else
1813
0
      {
1814
0
        bytes = 0;
1815
0
      }
1816
1817
0
      if (bytes == 0)
1818
0
      {
1819
0
        ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in;
1820
          // Additional bytes for buffer
1821
1822
0
        if (buflen > 0)
1823
0
        {
1824
0
          if (((z_stream *)http->stream)->avail_in > 0 && ((z_stream *)http->stream)->next_in > http->sbuffer)
1825
0
            memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
1826
1827
0
    ((z_stream *)http->stream)->next_in = http->sbuffer;
1828
1829
0
          DEBUG_printf("1httpRead2: Reading up to %d more bytes of data into decompression buffer.", (int)buflen);
1830
1831
0
          if (http->data_remaining > 0)
1832
0
          {
1833
0
      if (buflen > http->data_remaining)
1834
0
        buflen = (ssize_t)http->data_remaining;
1835
1836
0
      bytes = http_read_buffered(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
1837
0
          }
1838
0
          else if (http->data_encoding == HTTP_ENCODING_CHUNKED)
1839
0
          {
1840
0
            bytes = http_read_chunk(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
1841
0
          }
1842
0
          else
1843
0
          {
1844
0
            bytes = 0;
1845
0
    }
1846
1847
0
          if (bytes < 0)
1848
0
            return (bytes);
1849
0
          else if (bytes == 0)
1850
0
            break;
1851
1852
0
          DEBUG_printf("1httpRead2: Adding " CUPS_LLFMT " bytes to decompression buffer.", CUPS_LLCAST bytes);
1853
1854
0
          http->data_remaining  -= bytes;
1855
0
          ((z_stream *)http->stream)->avail_in += (uInt)bytes;
1856
1857
0
    if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
1858
0
    {
1859
      // Read the trailing blank line now...
1860
0
      char  len[32];    // Length string
1861
1862
0
      httpGets2(http, len, sizeof(len));
1863
0
    }
1864
1865
0
          bytes = 0;
1866
0
        }
1867
0
        else
1868
0
        {
1869
0
          return (0);
1870
0
  }
1871
0
      }
1872
0
    }
1873
0
    while (bytes == 0);
1874
0
  }
1875
0
  else if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
1876
0
  {
1877
0
    if ((bytes = http_read_chunk(http, buffer, length)) > 0)
1878
0
    {
1879
0
      http->data_remaining -= bytes;
1880
1881
0
      if (http->data_remaining <= 0)
1882
0
      {
1883
        // Read the trailing blank line now...
1884
0
        char  len[32];    // Length string
1885
1886
0
        httpGets2(http, len, sizeof(len));
1887
0
      }
1888
0
    }
1889
0
  }
1890
0
  else if (http->data_remaining <= 0)
1891
0
  {
1892
    // No more data to read...
1893
0
    return (0);
1894
0
  }
1895
0
  else
1896
0
  {
1897
0
    DEBUG_printf("1httpRead2: Reading up to %d bytes into buffer.", (int)length);
1898
1899
0
    if (length > (size_t)http->data_remaining)
1900
0
      length = (size_t)http->data_remaining;
1901
1902
0
    if ((bytes = http_read_buffered(http, buffer, length)) > 0)
1903
0
    {
1904
0
      http->data_remaining -= bytes;
1905
1906
0
      if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
1907
0
      {
1908
        // Read the trailing blank line now...
1909
0
        char  len[32];    // Length string
1910
1911
0
        httpGets2(http, len, sizeof(len));
1912
0
      }
1913
0
    }
1914
0
  }
1915
1916
0
  if ((http->coding == _HTTP_CODING_IDENTITY || (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)) && ((http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_LENGTH) || (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0)))
1917
0
  {
1918
0
    if (http->coding >= _HTTP_CODING_GUNZIP)
1919
0
      http_content_coding_finish(http);
1920
1921
0
    if (http->state == HTTP_STATE_POST_RECV)
1922
0
      http->state ++;
1923
0
    else if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND)
1924
0
      http->state = HTTP_STATE_WAITING;
1925
0
    else
1926
0
      http->state = HTTP_STATE_STATUS;
1927
1928
0
    DEBUG_printf("1httpRead2: End of content, set state to %s.", httpStateString(http->state));
1929
0
  }
1930
1931
0
  return (bytes);
1932
0
}
1933
1934
1935
//
1936
// 'httpReadRequest()' - Read a HTTP request from a connection.
1937
//
1938
// @since CUPS 1.7/macOS 10.9@
1939
//
1940
1941
http_state_t        // O - New state of connection
1942
httpReadRequest(http_t *http,   // I - HTTP connection
1943
                char   *uri,    // I - URI buffer
1944
    size_t urilen)    // I - Size of URI buffer
1945
0
{
1946
0
  char  line[4096],     // HTTP request line
1947
0
  *req_method,      // HTTP request method
1948
0
  *req_uri,     // HTTP request URI
1949
0
  *req_version;     // HTTP request version number string
1950
1951
1952
  // Range check input...
1953
0
  DEBUG_printf("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", (void *)http, (void *)uri, CUPS_LLCAST urilen);
1954
1955
0
  if (uri)
1956
0
    *uri = '\0';
1957
1958
0
  if (!http || !uri || urilen < 1)
1959
0
  {
1960
0
    DEBUG_puts("1httpReadRequest: Bad arguments, returning HTTP_STATE_ERROR.");
1961
0
    return (HTTP_STATE_ERROR);
1962
0
  }
1963
0
  else if (http->state != HTTP_STATE_WAITING)
1964
0
  {
1965
0
    DEBUG_printf("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.", httpStateString(http->state));
1966
0
    return (HTTP_STATE_ERROR);
1967
0
  }
1968
1969
  // Reset state...
1970
0
  httpClearFields(http);
1971
1972
0
  http->activity       = time(NULL);
1973
0
  http->data_encoding  = HTTP_ENCODING_FIELDS;
1974
0
  http->data_remaining = 0;
1975
0
  http->keep_alive     = HTTP_KEEPALIVE_OFF;
1976
0
  http->status         = HTTP_STATUS_OK;
1977
0
  http->version        = HTTP_VERSION_1_1;
1978
1979
  // Read a line from the socket...
1980
0
  if (!httpGets2(http, line, sizeof(line)))
1981
0
  {
1982
0
    DEBUG_puts("1httpReadRequest: Unable to read, returning HTTP_STATE_ERROR");
1983
0
    return (HTTP_STATE_ERROR);
1984
0
  }
1985
1986
0
  if (!line[0])
1987
0
  {
1988
0
    DEBUG_puts("1httpReadRequest: Blank line, returning HTTP_STATE_WAITING");
1989
0
    return (HTTP_STATE_WAITING);
1990
0
  }
1991
1992
0
  DEBUG_printf("1httpReadRequest: %s", line);
1993
1994
  // Parse it...
1995
0
  req_method = line;
1996
0
  req_uri    = line;
1997
1998
0
  while (*req_uri && !isspace(*req_uri & 255))
1999
0
    req_uri ++;
2000
2001
0
  if (!*req_uri)
2002
0
  {
2003
0
    DEBUG_puts("1httpReadRequest: No request URI.");
2004
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1);
2005
0
    return (HTTP_STATE_ERROR);
2006
0
  }
2007
2008
0
  *req_uri++ = '\0';
2009
2010
0
  while (*req_uri && isspace(*req_uri & 255))
2011
0
    req_uri ++;
2012
2013
0
  req_version = req_uri;
2014
2015
0
  while (*req_version && !isspace(*req_version & 255))
2016
0
    req_version ++;
2017
2018
0
  if (!*req_version)
2019
0
  {
2020
0
    DEBUG_puts("1httpReadRequest: No request protocol version.");
2021
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1);
2022
0
    return (HTTP_STATE_ERROR);
2023
0
  }
2024
2025
0
  *req_version++ = '\0';
2026
2027
0
  while (*req_version && isspace(*req_version & 255))
2028
0
    req_version ++;
2029
2030
  // Validate...
2031
0
  if (!strcmp(req_method, "OPTIONS"))
2032
0
  {
2033
0
    http->state = HTTP_STATE_OPTIONS;
2034
0
  }
2035
0
  else if (!strcmp(req_method, "GET"))
2036
0
  {
2037
0
    http->state = HTTP_STATE_GET;
2038
0
  }
2039
0
  else if (!strcmp(req_method, "HEAD"))
2040
0
  {
2041
0
    http->state = HTTP_STATE_HEAD;
2042
0
  }
2043
0
  else if (!strcmp(req_method, "POST"))
2044
0
  {
2045
0
    http->state = HTTP_STATE_POST;
2046
0
  }
2047
0
  else if (!strcmp(req_method, "PUT"))
2048
0
  {
2049
0
    http->state = HTTP_STATE_PUT;
2050
0
  }
2051
0
  else if (!strcmp(req_method, "DELETE"))
2052
0
  {
2053
0
    http->state = HTTP_STATE_DELETE;
2054
0
  }
2055
0
  else if (!strcmp(req_method, "TRACE"))
2056
0
  {
2057
0
    http->state = HTTP_STATE_TRACE;
2058
0
  }
2059
0
  else if (!strcmp(req_method, "CONNECT"))
2060
0
  {
2061
0
    http->state = HTTP_STATE_CONNECT;
2062
0
  }
2063
0
  else
2064
0
  {
2065
0
    DEBUG_printf("1httpReadRequest: Unknown method \"%s\".", req_method);
2066
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1);
2067
0
    return (HTTP_STATE_UNKNOWN_METHOD);
2068
0
  }
2069
2070
0
  DEBUG_printf("1httpReadRequest: Set state to %s.", httpStateString(http->state));
2071
2072
0
  if (!strcmp(req_version, "HTTP/1.0"))
2073
0
  {
2074
0
    http->version    = HTTP_VERSION_1_0;
2075
0
    http->keep_alive = HTTP_KEEPALIVE_OFF;
2076
0
  }
2077
0
  else if (!strcmp(req_version, "HTTP/1.1"))
2078
0
  {
2079
0
    http->version    = HTTP_VERSION_1_1;
2080
0
    http->keep_alive = HTTP_KEEPALIVE_ON;
2081
0
  }
2082
0
  else
2083
0
  {
2084
0
    DEBUG_printf("1httpReadRequest: Unknown version \"%s\".", req_version);
2085
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1);
2086
0
    return (HTTP_STATE_UNKNOWN_VERSION);
2087
0
  }
2088
2089
0
  DEBUG_printf("1httpReadRequest: URI is \"%s\".", req_uri);
2090
0
  cupsCopyString(uri, req_uri, urilen);
2091
2092
0
  return (http->state);
2093
0
}
2094
2095
2096
//
2097
// 'httpReconnect()' - Reconnect to a HTTP server.
2098
//
2099
// This function is deprecated. Please use the @link httpReconnect2@ function
2100
// instead.
2101
//
2102
// @deprecated@ @exclude all@
2103
//
2104
2105
int         // O - 0 on success, non-zero on failure
2106
httpReconnect(http_t *http)   // I - HTTP connection
2107
0
{
2108
0
  DEBUG_printf("httpReconnect(http=%p)", (void *)http);
2109
2110
0
  return (httpReconnect2(http, 30000, NULL));
2111
0
}
2112
2113
2114
//
2115
// 'httpReconnect2()' - Reconnect to a HTTP server with timeout and optional
2116
//                      cancel.
2117
//
2118
2119
int         // O - 0 on success, non-zero on failure
2120
httpReconnect2(http_t *http,    // I - HTTP connection
2121
         int    msec,   // I - Timeout in milliseconds
2122
         int    *cancel)    // I - Pointer to "cancel" variable
2123
0
{
2124
0
  http_addrlist_t *addr;    // Connected address
2125
#ifdef DEBUG
2126
  http_addrlist_t *current; // Current address
2127
  char      temp[256];  // Temporary address string
2128
#endif // DEBUG
2129
2130
2131
0
  DEBUG_printf("httpReconnect2(http=%p, msec=%d, cancel=%p)", (void *)http, msec, (void *)cancel);
2132
2133
0
  if (!http)
2134
0
  {
2135
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
2136
0
    return (-1);
2137
0
  }
2138
2139
0
  if (http->tls)
2140
0
  {
2141
0
    DEBUG_puts("2httpReconnect2: Shutting down TLS...");
2142
0
    _httpTLSStop(http);
2143
0
  }
2144
2145
  // Close any previously open socket...
2146
0
  if (http->fd >= 0)
2147
0
  {
2148
0
    DEBUG_printf("2httpReconnect2: Closing socket %d...", http->fd);
2149
2150
0
    httpAddrClose(NULL, http->fd);
2151
2152
0
    http->fd = -1;
2153
0
  }
2154
2155
  // Reset all state (except fields, which may be reused)...
2156
0
  http->state           = HTTP_STATE_WAITING;
2157
0
  http->version         = HTTP_VERSION_1_1;
2158
0
  http->keep_alive      = HTTP_KEEPALIVE_OFF;
2159
0
  memset(&http->_hostaddr, 0, sizeof(http->_hostaddr));
2160
0
  http->data_encoding   = HTTP_ENCODING_FIELDS;
2161
0
  http->_data_remaining = 0;
2162
0
  http->used            = 0;
2163
0
  http->data_remaining  = 0;
2164
0
  http->hostaddr        = NULL;
2165
0
  http->wused           = 0;
2166
2167
  // Connect to the server...
2168
#ifdef DEBUG
2169
  for (current = http->addrlist; current; current = current->next)
2170
    DEBUG_printf("2httpReconnect2: Address %s:%d", httpAddrString(&(current->addr), temp, sizeof(temp)), httpAddrPort(&(current->addr)));
2171
#endif // DEBUG
2172
2173
0
  if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL)
2174
0
  {
2175
    // Unable to connect...
2176
#ifdef _WIN32
2177
    http->error  = WSAGetLastError();
2178
#else
2179
0
    http->error  = errno;
2180
0
#endif // _WIN32
2181
0
    http->status = HTTP_STATUS_ERROR;
2182
2183
0
    DEBUG_printf("1httpReconnect2: httpAddrConnect failed: %s", strerror(http->error));
2184
2185
0
    return (-1);
2186
0
  }
2187
2188
0
  DEBUG_printf("2httpReconnect2: New socket=%d", http->fd);
2189
2190
0
  if (http->timeout_value > 0)
2191
0
    http_set_timeout(http->fd, http->timeout_value);
2192
2193
0
  http->hostaddr = &(addr->addr);
2194
0
  http->error    = 0;
2195
2196
0
  if (http->encryption == HTTP_ENCRYPTION_ALWAYS)
2197
0
  {
2198
    // Always do encryption via TLS.
2199
0
    if (!_httpTLSStart(http))
2200
0
    {
2201
0
      httpAddrClose(NULL, http->fd);
2202
0
      http->fd = -1;
2203
2204
0
      return (-1);
2205
0
    }
2206
0
  }
2207
0
  else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade)
2208
0
    return (http_tls_upgrade(http) ? 0 : -1);
2209
2210
0
  DEBUG_printf("1httpReconnect2: Connected to %s:%d...", httpAddrGetString(http->hostaddr, temp, sizeof(temp)), httpAddrGetPort(http->hostaddr));
2211
2212
0
  return (0);
2213
0
}
2214
2215
2216
//
2217
// 'httpSetAuthString()' - Set the current authorization string.
2218
//
2219
// This function just stores a copy of the current authorization string in
2220
// the HTTP connection object.  You must still call @link httpSetField@ to set
2221
// `HTTP_FIELD_AUTHORIZATION` prior to issuing a HTTP request using
2222
// @link httpWriteRequest@.
2223
//
2224
// @since CUPS 1.3/macOS 10.5@
2225
//
2226
2227
void
2228
httpSetAuthString(http_t     *http, // I - HTTP connection
2229
                  const char *scheme, // I - Auth scheme (NULL to clear it)
2230
      const char *data) // I - Auth data (NULL for none)
2231
0
{
2232
  // Range check input...
2233
0
  if (!http)
2234
0
    return;
2235
2236
0
  if (http->authstring && http->authstring != http->_authstring)
2237
0
    free(http->authstring);
2238
2239
0
  http->authstring = http->_authstring;
2240
2241
0
  if (scheme)
2242
0
  {
2243
    // Set the current authorization string...
2244
0
    size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
2245
0
    char *temp;
2246
2247
0
    if (len > sizeof(http->_authstring))
2248
0
    {
2249
0
      if ((temp = malloc(len)) == NULL)
2250
0
        len = sizeof(http->_authstring);
2251
0
      else
2252
0
        http->authstring = temp;
2253
0
    }
2254
2255
0
    if (data)
2256
0
      snprintf(http->authstring, len, "%s %s", scheme, data);
2257
0
    else
2258
0
      cupsCopyString(http->authstring, scheme, len);
2259
0
  }
2260
0
  else
2261
0
  {
2262
    // Clear the current authorization string...
2263
0
    http->_authstring[0] = '\0';
2264
0
  }
2265
0
}
2266
2267
2268
//
2269
// 'httpSetBlocking()' - Set blocking/non-blocking behavior on a connection.
2270
//
2271
2272
void
2273
httpSetBlocking(http_t *http,   // I - HTTP connection
2274
                bool   b)   // I - `true` for blocking, `false` for non-blocking
2275
0
{
2276
0
  if (http)
2277
0
  {
2278
0
    http->blocking = b ? 1 : 0;
2279
0
    http_set_wait(http);
2280
0
  }
2281
0
}
2282
2283
2284
//
2285
// 'httpSetCredentials()' - Set the credentials associated with an encrypted connection.
2286
//
2287
// @deprecated@ @exclude all@
2288
//
2289
2290
int           // O - Status of call (0 = success)
2291
httpSetCredentials(http_t *http,    // I - HTTP connection
2292
       cups_array_t *credentials) // I - Array of credentials
2293
0
{
2294
0
  (void)http;
2295
0
  (void)credentials;
2296
2297
0
  return (-1);
2298
0
}
2299
2300
2301
//
2302
// 'httpSetCookie()' - Set the cookie value(s).
2303
//
2304
// @since CUPS 1.1.19/macOS 10.3@
2305
//
2306
2307
void
2308
httpSetCookie(http_t     *http,   // I - Connection
2309
              const char *cookie) // I - Cookie string
2310
0
{
2311
0
  if (!http)
2312
0
    return;
2313
2314
0
  if (http->cookie)
2315
0
    free(http->cookie);
2316
2317
0
  if (cookie)
2318
0
    http->cookie = strdup(cookie);
2319
0
  else
2320
0
    http->cookie = NULL;
2321
0
}
2322
2323
2324
//
2325
// 'httpSetDefaultField()' - Set the default value of an HTTP header.
2326
//
2327
// Currently only `HTTP_FIELD_ACCEPT_ENCODING`, `HTTP_FIELD_SERVER`,
2328
// and `HTTP_FIELD_USER_AGENT` can be set.
2329
//
2330
// @since CUPS 1.7/macOS 10.9@
2331
//
2332
2333
void
2334
httpSetDefaultField(http_t       *http, // I - HTTP connection
2335
                    http_field_t field, // I - Field index
2336
              const char   *value)// I - Value
2337
0
{
2338
0
  DEBUG_printf("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value);
2339
2340
0
  if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
2341
0
    return;
2342
2343
0
  if (http->default_fields[field])
2344
0
    free(http->default_fields[field]);
2345
2346
0
  http->default_fields[field] = value ? strdup(value) : NULL;
2347
0
}
2348
2349
2350
//
2351
// 'httpSetEncryption()' - Set the required encryption on the link.
2352
//
2353
// @since CUPS 2.5@
2354
//
2355
2356
bool          // O - `true` on success, `false` on error
2357
httpSetEncryption(
2358
    http_t            *http,    // I - HTTP connection
2359
    http_encryption_t e)    // I - New encryption preference
2360
0
{
2361
0
  DEBUG_printf("httpSetEncryption(http=%p, e=%d)", (void *)http, e);
2362
2363
0
  if (!http)
2364
0
    return (true);
2365
2366
0
  if (http->mode == _HTTP_MODE_CLIENT)
2367
0
  {
2368
0
    http->encryption = e;
2369
2370
0
    if ((http->encryption == HTTP_ENCRYPTION_ALWAYS && !http->tls) || (http->encryption == HTTP_ENCRYPTION_NEVER && http->tls))
2371
0
      return (!httpReconnect2(http, 30000, NULL));
2372
0
    else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
2373
0
      return (http_tls_upgrade(http));
2374
0
    else
2375
0
      return (true);
2376
0
  }
2377
0
  else
2378
0
  {
2379
0
    if (e == HTTP_ENCRYPTION_NEVER && http->tls)
2380
0
      return (true);
2381
2382
0
    http->encryption = e;
2383
0
    if (e != HTTP_ENCRYPTION_IF_REQUESTED && !http->tls)
2384
0
      return (_httpTLSStart(http));
2385
0
    else
2386
0
      return (true);
2387
0
  }
2388
0
}
2389
2390
2391
//
2392
// 'httpSetExpect()' - Set the Expect: header in a request.
2393
//
2394
// Currently only `HTTP_STATUS_CONTINUE` is supported for the "expect"
2395
// argument.
2396
//
2397
// @since CUPS 1.2/macOS 10.5@
2398
//
2399
2400
void
2401
httpSetExpect(http_t        *http,  // I - HTTP connection
2402
              http_status_t expect) // I - HTTP status to expect (`HTTP_STATUS_CONTINUE`)
2403
0
{
2404
0
  DEBUG_printf("httpSetExpect(http=%p, expect=%d)", (void *)http, expect);
2405
2406
0
  if (http)
2407
0
    http->expect = expect;
2408
0
}
2409
2410
2411
//
2412
// 'httpSetField()' - Set the value of an HTTP header.
2413
//
2414
2415
void
2416
httpSetField(http_t       *http,  // I - HTTP connection
2417
             http_field_t field,  // I - Field index
2418
       const char   *value) // I - Value
2419
0
{
2420
0
  DEBUG_printf("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value);
2421
2422
0
  if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !value)
2423
0
    return;
2424
2425
0
  http_add_field(http, field, value, 0);
2426
0
}
2427
2428
2429
//
2430
// 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
2431
//
2432
// @since CUPS 2.0/OS 10.10@
2433
//
2434
2435
void
2436
httpSetKeepAlive(
2437
    http_t           *http,   // I - HTTP connection
2438
    http_keepalive_t keep_alive)  // I - New Keep-Alive value
2439
0
{
2440
0
  if (http)
2441
0
    http->keep_alive = keep_alive;
2442
0
}
2443
2444
2445
//
2446
// 'httpSetLength()' - Set the content-length and content-encoding.
2447
//
2448
// @since CUPS 1.2/macOS 10.5@
2449
//
2450
2451
void
2452
httpSetLength(http_t *http,   // I - HTTP connection
2453
              size_t length)    // I - Length (0 for chunked)
2454
0
{
2455
0
  DEBUG_printf("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length);
2456
2457
0
  if (!http)
2458
0
    return;
2459
2460
0
  if (!length)
2461
0
  {
2462
0
    httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
2463
0
    httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "");
2464
0
  }
2465
0
  else
2466
0
  {
2467
0
    char len[32];     // Length string
2468
2469
0
    snprintf(len, sizeof(len), CUPS_LLFMT, CUPS_LLCAST length);
2470
0
    httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "");
2471
0
    httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, len);
2472
0
  }
2473
0
}
2474
2475
2476
//
2477
// 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
2478
//
2479
// The optional timeout callback receives both the HTTP connection and a user
2480
// data pointer and must return 1 to continue or 0 to error (time) out.
2481
//
2482
// @since CUPS 1.5/macOS 10.7@
2483
//
2484
2485
void
2486
httpSetTimeout(
2487
    http_t            *http,    // I - HTTP connection
2488
    double            timeout,    // I - Number of seconds for timeout, must be greater than `0.0`
2489
    http_timeout_cb_t cb,   // I - Callback function or `NULL`
2490
    void              *user_data) // I - User data pointer
2491
0
{
2492
0
  if (!http || timeout <= 0.0)
2493
0
    return;
2494
2495
0
  http->timeout_cb    = cb;
2496
0
  http->timeout_data  = user_data;
2497
0
  http->timeout_value = timeout;
2498
2499
0
  if (http->fd >= 0)
2500
0
    http_set_timeout(http->fd, timeout);
2501
2502
0
  http_set_wait(http);
2503
0
}
2504
2505
2506
//
2507
// 'httpShutdown()' - Shutdown one side of an HTTP connection.
2508
//
2509
// @since CUPS 2.0/OS 10.10@
2510
//
2511
2512
void
2513
httpShutdown(http_t *http)    // I - HTTP connection
2514
0
{
2515
0
  if (!http || http->fd < 0)
2516
0
    return;
2517
2518
0
  if (http->tls)
2519
0
    _httpTLSStop(http);
2520
2521
#ifdef _WIN32
2522
  shutdown(http->fd, SD_RECEIVE); // Microsoft-ism...
2523
#else
2524
0
  shutdown(http->fd, SHUT_RD);
2525
0
#endif // _WIN32
2526
0
}
2527
2528
2529
//
2530
// 'httpTrace()' - Send an TRACE request to the server.
2531
//
2532
// @deprecated@ @exclude all@
2533
//
2534
2535
int         // O - Status of call (0 = success)
2536
httpTrace(http_t     *http,   // I - HTTP connection
2537
          const char *uri)    // I - URI for trace
2538
0
{
2539
0
  return (http_send(http, HTTP_STATE_TRACE, uri) ? 0 : -1);
2540
0
}
2541
2542
2543
//
2544
// '_httpUpdate()' - Update the current HTTP status for incoming data.
2545
//
2546
// Note: Unlike httpUpdate(), this function does not flush pending write data
2547
// and only retrieves a single status line from the HTTP connection.
2548
//
2549
2550
int         // O - 1 to continue, 0 to stop
2551
_httpUpdate(http_t        *http,  // I - HTTP connection
2552
            http_status_t *status)  // O - Current HTTP status
2553
0
{
2554
0
  char    line[32768],    // Line from connection...
2555
0
    *value;     // Pointer to value on line
2556
0
  http_field_t  field;      // Field index
2557
0
  int   major, minor;   // HTTP version numbers
2558
2559
2560
0
  DEBUG_printf("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state));
2561
2562
  // Grab a single line from the connection...
2563
0
  if (!httpGets2(http, line, sizeof(line)))
2564
0
  {
2565
0
    *status = HTTP_STATUS_ERROR;
2566
0
    return (0);
2567
0
  }
2568
2569
0
  DEBUG_printf("2_httpUpdate: Got \"%s\"", line);
2570
2571
0
  if (line[0] == '\0')
2572
0
  {
2573
    // Blank line means the start of the data section (if any).  Return
2574
    // the result code, too...
2575
    //
2576
    // If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
2577
    // states.  Instead, we just return HTTP_STATUS_CONTINUE to the caller and
2578
    // keep on tryin'...
2579
0
    if (http->status == HTTP_STATUS_CONTINUE)
2580
0
    {
2581
0
      *status = http->status;
2582
0
      return (0);
2583
0
    }
2584
2585
0
    if (http->status < HTTP_STATUS_BAD_REQUEST)
2586
0
      http->digest_tries = 0;
2587
2588
0
    if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
2589
0
    {
2590
0
      if (!_httpTLSStart(http))
2591
0
      {
2592
0
        httpAddrClose(NULL, http->fd);
2593
0
        http->fd = -1;
2594
2595
0
  *status = http->status = HTTP_STATUS_ERROR;
2596
0
  return (0);
2597
0
      }
2598
2599
0
      *status = HTTP_STATUS_CONTINUE;
2600
0
      return (0);
2601
0
    }
2602
2603
0
    if (http_set_length(http) < 0)
2604
0
    {
2605
0
      DEBUG_puts("1_httpUpdate: Bad Content-Length.");
2606
0
      http->error  = EINVAL;
2607
0
      http->status = *status = HTTP_STATUS_ERROR;
2608
0
      return (0);
2609
0
    }
2610
2611
0
    switch (http->state)
2612
0
    {
2613
0
      case HTTP_STATE_GET :
2614
0
      case HTTP_STATE_POST :
2615
0
      case HTTP_STATE_POST_RECV :
2616
0
      case HTTP_STATE_PUT :
2617
0
    http->state ++;
2618
2619
0
    DEBUG_printf("1_httpUpdate: Set state to %s.", httpStateString(http->state));
2620
2621
0
      case HTTP_STATE_POST_SEND :
2622
0
      case HTTP_STATE_HEAD :
2623
0
    break;
2624
2625
0
      default :
2626
0
    http->state = HTTP_STATE_WAITING;
2627
2628
0
    DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
2629
0
    break;
2630
0
    }
2631
2632
0
    DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
2633
0
    http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
2634
2635
0
    *status = http->status;
2636
0
    return (0);
2637
0
  }
2638
0
  else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
2639
0
  {
2640
    // Got the beginning of a response...
2641
0
    int intstatus;      // Status value as an integer
2642
2643
0
    if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
2644
0
    {
2645
0
      *status = http->status = HTTP_STATUS_ERROR;
2646
0
      return (0);
2647
0
    }
2648
2649
0
    httpClearFields(http);
2650
2651
0
    http->version = (http_version_t)(major * 100 + minor);
2652
0
    *status       = http->status = (http_status_t)intstatus;
2653
0
  }
2654
0
  else if ((value = strchr(line, ':')) != NULL)
2655
0
  {
2656
    // Got a value...
2657
0
    *value++ = '\0';
2658
0
    while (_cups_isspace(*value))
2659
0
      value ++;
2660
2661
0
    DEBUG_printf("1_httpUpdate: Header %s: %s", line, value);
2662
2663
    // Be tolerants of servers that send unknown attribute fields...
2664
0
    if (!_cups_strcasecmp(line, "expect"))
2665
0
    {
2666
      // "Expect: 100-continue" or similar...
2667
0
      http->expect = (http_status_t)atoi(value);
2668
0
    }
2669
0
    else if (!_cups_strcasecmp(line, "cookie"))
2670
0
    {
2671
      // "Cookie: name=value[; name=value ...]" - replaces previous cookies...
2672
0
      httpSetCookie(http, value);
2673
0
    }
2674
0
    else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
2675
0
    {
2676
0
      http_add_field(http, field, value, 1);
2677
2678
0
      if (field == HTTP_FIELD_AUTHENTICATION_INFO)
2679
0
        httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce));
2680
0
    }
2681
#ifdef DEBUG
2682
    else
2683
    {
2684
      DEBUG_printf("1_httpUpdate: unknown field %s seen!", line);
2685
    }
2686
#endif // DEBUG
2687
0
  }
2688
0
  else
2689
0
  {
2690
0
    DEBUG_printf("1_httpUpdate: Bad response line \"%s\"!", line);
2691
0
    http->error  = EINVAL;
2692
0
    http->status = *status = HTTP_STATUS_ERROR;
2693
0
    return (0);
2694
0
  }
2695
2696
0
  return (1);
2697
0
}
2698
2699
2700
//
2701
// 'httpUpdate()' - Update the current HTTP state for incoming data.
2702
//
2703
2704
http_status_t       // O - HTTP status
2705
httpUpdate(http_t *http)    // I - HTTP connection
2706
0
{
2707
0
  http_status_t status;     // Request status
2708
2709
2710
0
  DEBUG_printf("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state));
2711
2712
  // Flush pending data, if any...
2713
0
  if (http->wused)
2714
0
  {
2715
0
    DEBUG_puts("2httpUpdate: flushing buffer...");
2716
2717
0
    if (httpFlushWrite(http) < 0)
2718
0
      return (HTTP_STATUS_ERROR);
2719
0
  }
2720
2721
  // If we haven't issued any commands, then there is nothing to "update"...
2722
0
  if (http->state == HTTP_STATE_WAITING)
2723
0
    return (HTTP_STATUS_CONTINUE);
2724
2725
  // Grab all of the lines we can from the connection...
2726
0
  while (_httpUpdate(http, &status))
2727
0
    ; // Update as needed...
2728
2729
  // See if there was an error...
2730
0
  if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
2731
0
  {
2732
0
    DEBUG_printf("1httpUpdate: Returning status %d...", http->status);
2733
0
    return (http->status);
2734
0
  }
2735
2736
0
  if (http->error)
2737
0
  {
2738
0
    DEBUG_printf("1httpUpdate: socket error %d - %s", http->error, strerror(http->error));
2739
0
    http->status = HTTP_STATUS_ERROR;
2740
0
    return (HTTP_STATUS_ERROR);
2741
0
  }
2742
2743
  // Return the current status...
2744
0
  return (status);
2745
0
}
2746
2747
2748
//
2749
// '_httpWait()' - Wait for data available on a connection (no flush).
2750
//
2751
2752
int         // O - 1 if data is available, 0 otherwise
2753
_httpWait(http_t *http,     // I - HTTP connection
2754
          int    msec,      // I - Milliseconds to wait
2755
    int    usessl)    // I - Use TLS context?
2756
0
{
2757
0
  struct pollfd   pfd;    // Polled file descriptor
2758
0
  int     nfds;   // Result from select()/poll()
2759
2760
2761
0
  DEBUG_printf("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl);
2762
2763
0
  if (http->fd < 0)
2764
0
  {
2765
0
    DEBUG_printf("5_httpWait: Returning 0 since fd=%d", http->fd);
2766
0
    return (0);
2767
0
  }
2768
2769
  // Check the TLS buffers for data first...
2770
0
  if (http->tls && _httpTLSPending(http))
2771
0
  {
2772
0
    DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
2773
0
    return (1);
2774
0
  }
2775
2776
  // Then try doing a select() or poll() to poll the socket...
2777
0
  pfd.fd     = http->fd;
2778
0
  pfd.events = POLLIN;
2779
2780
0
  do
2781
0
  {
2782
0
    nfds = poll(&pfd, 1, msec);
2783
0
  }
2784
#ifdef _WIN32
2785
  while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
2786
#else
2787
0
  while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
2788
0
#endif // _WIN32
2789
2790
0
  DEBUG_printf("5_httpWait: returning with nfds=%d, errno=%d...", nfds, errno);
2791
2792
0
  return (nfds > 0);
2793
0
}
2794
2795
2796
//
2797
// 'httpWait()' - Wait for data available on a connection.
2798
//
2799
// @since CUPS 1.1.19/macOS 10.3@
2800
//
2801
2802
int         // O - 1 if data is available, 0 otherwise
2803
httpWait(http_t *http,      // I - HTTP connection
2804
         int    msec)     // I - Milliseconds to wait
2805
0
{
2806
  // First see if there is data in the buffer...
2807
0
  DEBUG_printf("2httpWait(http=%p, msec=%d)", (void *)http, msec);
2808
2809
0
  if (http == NULL)
2810
0
    return (0);
2811
2812
0
  if (http->used)
2813
0
  {
2814
0
    DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
2815
0
    return (1);
2816
0
  }
2817
2818
0
  if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0)
2819
0
  {
2820
0
    DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
2821
0
    return (1);
2822
0
  }
2823
2824
  // Flush pending data, if any...
2825
0
  if (http->wused)
2826
0
  {
2827
0
    DEBUG_puts("3httpWait: Flushing write buffer.");
2828
2829
0
    if (httpFlushWrite(http) < 0)
2830
0
      return (0);
2831
0
  }
2832
2833
  // If not, check the TLS buffers and do a select() on the connection...
2834
0
  return (_httpWait(http, msec, 1));
2835
0
}
2836
2837
2838
//
2839
// 'httpWrite()' - Write data to a HTTP connection.
2840
//
2841
// This function is deprecated. Use the httpWrite2() function which can
2842
// write more than 2GB of data.
2843
//
2844
// @deprecated@ @exclude all@
2845
//
2846
2847
int         // O - Number of bytes written
2848
httpWrite(http_t     *http,   // I - HTTP connection
2849
          const char *buffer,   // I - Buffer for data
2850
    int        length)    // I - Number of bytes to write
2851
0
{
2852
0
  return ((int)httpWrite2(http, buffer, (size_t)length));
2853
0
}
2854
2855
2856
//
2857
// 'httpWrite2()' - Write data to a HTTP connection.
2858
//
2859
// @since CUPS 1.2/macOS 10.5@
2860
//
2861
2862
ssize_t         // O - Number of bytes written
2863
httpWrite2(http_t     *http,    // I - HTTP connection
2864
           const char *buffer,    // I - Buffer for data
2865
     size_t     length)   // I - Number of bytes to write
2866
0
{
2867
0
  ssize_t bytes;      // Bytes written
2868
2869
2870
0
  DEBUG_printf("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length);
2871
2872
  // Range check input...
2873
0
  if (!http || !buffer)
2874
0
  {
2875
0
    DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
2876
0
    return (-1);
2877
0
  }
2878
2879
  // Mark activity on the connection...
2880
0
  http->activity = time(NULL);
2881
2882
  // Buffer small writes for better performance...
2883
0
  if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
2884
0
  {
2885
0
    DEBUG_printf("1httpWrite2: http->coding=%d", http->coding);
2886
2887
0
    if (length == 0)
2888
0
    {
2889
0
      http_content_coding_finish(http);
2890
0
      bytes = 0;
2891
0
    }
2892
0
    else
2893
0
    {
2894
0
      size_t  slen;     // Bytes to write
2895
0
      ssize_t sret;     // Bytes written
2896
2897
0
      ((z_stream *)http->stream)->next_in   = (Bytef *)buffer;
2898
0
      ((z_stream *)http->stream)->avail_in  = (uInt)length;
2899
2900
0
      while (deflate((z_stream *)http->stream, Z_NO_FLUSH) == Z_OK)
2901
0
      {
2902
0
        DEBUG_printf("1httpWrite2: avail_out=%d", ((z_stream *)http->stream)->avail_out);
2903
2904
0
        if (((z_stream *)http->stream)->avail_out > 0)
2905
0
    continue;
2906
2907
0
  slen = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
2908
2909
0
        DEBUG_printf("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen);
2910
2911
0
  if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
2912
0
    sret = http_write_chunk(http, (char *)http->sbuffer, slen);
2913
0
  else if (slen > 0)
2914
0
    sret = http_write(http, (char *)http->sbuffer, slen);
2915
0
  else
2916
0
    sret = 0;
2917
2918
0
        if (sret < 0)
2919
0
  {
2920
0
    DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
2921
0
    return (-1);
2922
0
  }
2923
2924
0
  ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
2925
0
  ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
2926
0
      }
2927
2928
0
      bytes = (ssize_t)length;
2929
0
    }
2930
0
  }
2931
0
  else if (length > 0)
2932
0
  {
2933
0
    if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
2934
0
    {
2935
0
      DEBUG_printf("2httpWrite2: Flushing buffer (wused=%d, length=" CUPS_LLFMT ")", http->wused, CUPS_LLCAST length);
2936
2937
0
      httpFlushWrite(http);
2938
0
    }
2939
2940
0
    if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer))
2941
0
    {
2942
      // Write to buffer...
2943
0
      DEBUG_printf("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...", CUPS_LLCAST length);
2944
2945
0
      memcpy(http->wbuffer + http->wused, buffer, length);
2946
0
      http->wused += (int)length;
2947
0
      bytes = (ssize_t)length;
2948
0
    }
2949
0
    else
2950
0
    {
2951
      // Otherwise write the data directly...
2952
0
      DEBUG_printf("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...", CUPS_LLCAST length);
2953
2954
0
      if (http->data_encoding == HTTP_ENCODING_CHUNKED)
2955
0
  bytes = http_write_chunk(http, buffer, length);
2956
0
      else
2957
0
  bytes = http_write(http, buffer, length);
2958
2959
0
      DEBUG_printf("2httpWrite2: Wrote " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes);
2960
0
    }
2961
2962
0
    if (http->data_encoding == HTTP_ENCODING_LENGTH)
2963
0
      http->data_remaining -= bytes;
2964
0
  }
2965
0
  else
2966
0
  {
2967
0
    bytes = 0;
2968
0
  }
2969
2970
  // Handle end-of-request processing...
2971
0
  if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) || (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0))
2972
0
  {
2973
    // Finished with the transfer; unless we are sending POST or PUT data, go idle...
2974
0
    if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
2975
0
      http_content_coding_finish(http);
2976
2977
0
    if (http->wused)
2978
0
    {
2979
0
      if (httpFlushWrite(http) < 0)
2980
0
        return (-1);
2981
0
    }
2982
2983
0
    if (http->data_encoding == HTTP_ENCODING_CHUNKED)
2984
0
    {
2985
      // Send a 0-length chunk at the end of the request...
2986
0
      http_write(http, "0\r\n\r\n", 5);
2987
2988
      // Reset the data state...
2989
0
      http->data_encoding  = HTTP_ENCODING_FIELDS;
2990
0
      http->data_remaining = 0;
2991
0
    }
2992
2993
0
    if (http->state == HTTP_STATE_POST_RECV)
2994
0
      http->state ++;
2995
0
    else if (http->state == HTTP_STATE_POST_SEND || http->state == HTTP_STATE_GET_SEND)
2996
0
      http->state = HTTP_STATE_WAITING;
2997
0
    else
2998
0
      http->state = HTTP_STATE_STATUS;
2999
3000
0
    DEBUG_printf("2httpWrite2: Changed state to %s.", httpStateString(http->state));
3001
0
  }
3002
3003
0
  DEBUG_printf("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes);
3004
3005
0
  return (bytes);
3006
0
}
3007
3008
3009
//
3010
// 'httpWriteRequest()' - Send a HTTP request.
3011
//
3012
// @since CUPS 2.5@
3013
//
3014
3015
bool          // O - `true` on success, `false` on error
3016
httpWriteRequest(http_t     *http,  // I - HTTP connection
3017
                 const char *method,  // I - Method string ("GET", "POST", etc.)
3018
                 const char *uri) // I - URI
3019
0
{
3020
0
  if (!strcasecmp(method, "DELETE"))
3021
0
    return (http_send(http, HTTP_STATE_DELETE, uri));
3022
0
  else if (!strcasecmp(method, "GET"))
3023
0
    return (http_send(http, HTTP_STATE_GET, uri));
3024
0
  else if (!strcasecmp(method, "HEAD"))
3025
0
    return (http_send(http, HTTP_STATE_HEAD, uri));
3026
0
  else if (!strcasecmp(method, "OPTIONS"))
3027
0
    return (http_send(http, HTTP_STATE_OPTIONS, uri));
3028
0
  else if (!strcasecmp(method, "POST"))
3029
0
    return (http_send(http, HTTP_STATE_POST, uri));
3030
0
  else if (!strcasecmp(method, "PUT"))
3031
0
    return (http_send(http, HTTP_STATE_PUT, uri));
3032
0
  else if (!strcasecmp(method, "TRACE"))
3033
0
    return (http_send(http, HTTP_STATE_TRACE, uri));
3034
0
  else
3035
0
    return (false);
3036
0
}
3037
3038
3039
//
3040
// 'httpWriteResponse()' - Write a HTTP response to a client connection.
3041
//
3042
// @since CUPS 1.7/macOS 10.9@
3043
//
3044
3045
int         // O - 0 on success, -1 on error
3046
httpWriteResponse(http_t        *http,  // I - HTTP connection
3047
      http_status_t status) // I - Status code
3048
0
{
3049
0
  http_encoding_t old_encoding; // Old data_encoding value
3050
0
  off_t     old_remaining;  // Old data_remaining value
3051
0
  cups_lang_t   *lang;    // Response language
3052
3053
3054
  // Range check input...
3055
0
  DEBUG_printf("httpWriteResponse(http=%p, status=%d)", (void *)http, status);
3056
3057
0
  if (!http || status < HTTP_STATUS_CONTINUE)
3058
0
  {
3059
0
    DEBUG_puts("1httpWriteResponse: Bad input.");
3060
0
    return (-1);
3061
0
  }
3062
3063
  // Set the various standard fields if they aren't already...
3064
0
  if (!http->fields[HTTP_FIELD_DATE])
3065
0
    httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
3066
3067
0
  if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
3068
0
  {
3069
0
    http->keep_alive = HTTP_KEEPALIVE_OFF;
3070
0
    httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
3071
0
  }
3072
3073
0
  if (http->version == HTTP_VERSION_1_1)
3074
0
  {
3075
0
    if (!http->fields[HTTP_FIELD_CONNECTION])
3076
0
    {
3077
0
      if (http->keep_alive)
3078
0
  httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
3079
0
      else
3080
0
  httpSetField(http, HTTP_FIELD_CONNECTION, "close");
3081
0
    }
3082
3083
0
    if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE])
3084
0
      httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
3085
0
  }
3086
3087
0
  if (status == HTTP_STATUS_UPGRADE_REQUIRED || status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3088
0
  {
3089
0
    if (!http->fields[HTTP_FIELD_CONNECTION])
3090
0
      httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3091
3092
0
    if (!http->fields[HTTP_FIELD_UPGRADE])
3093
0
      httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
3094
3095
0
    if (!http->fields[HTTP_FIELD_CONTENT_LENGTH])
3096
0
      httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
3097
0
  }
3098
3099
0
  if (!http->fields[HTTP_FIELD_SERVER])
3100
0
    httpSetField(http, HTTP_FIELD_SERVER, http->default_fields[HTTP_FIELD_SERVER] ? http->default_fields[HTTP_FIELD_SERVER] : CUPS_MINIMAL);
3101
3102
  // Set the Accept-Encoding field if it isn't already...
3103
0
  if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING])
3104
0
    httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] ? http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] : "gzip, deflate, identity");
3105
3106
  // Get the response language, if any...
3107
0
  lang = cupsLangGet(http->fields[HTTP_FIELD_CONTENT_LANGUAGE]);
3108
3109
  // Send the response header...
3110
0
  old_encoding        = http->data_encoding;
3111
0
  old_remaining       = http->data_remaining;
3112
0
  http->data_encoding = HTTP_ENCODING_FIELDS;
3113
3114
0
  if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100, http->version % 100, (int)status, _httpStatusString(lang, status)) < 0)
3115
0
  {
3116
0
    http->status = HTTP_STATUS_ERROR;
3117
0
    return (-1);
3118
0
  }
3119
3120
0
  if (status != HTTP_STATUS_CONTINUE)
3121
0
  {
3122
    // 100 Continue doesn't have the rest of the response headers...
3123
0
    int   i;      // Looping var
3124
0
    const char  *value;     // Field value
3125
3126
0
    for (i = 0; i < HTTP_FIELD_MAX; i ++)
3127
0
    {
3128
0
      if ((value = httpGetField(http, i)) != NULL && *value)
3129
0
      {
3130
0
  if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
3131
0
  {
3132
0
    http->status = HTTP_STATUS_ERROR;
3133
0
    return (-1);
3134
0
  }
3135
0
      }
3136
0
    }
3137
3138
0
    if (http->cookie)
3139
0
    {
3140
0
      if (strchr(http->cookie, ';'))
3141
0
      {
3142
0
        if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1)
3143
0
  {
3144
0
    http->status = HTTP_STATUS_ERROR;
3145
0
    return (-1);
3146
0
  }
3147
0
      }
3148
0
      else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1)
3149
0
      {
3150
0
  http->status = HTTP_STATUS_ERROR;
3151
0
  return (-1);
3152
0
      }
3153
0
    }
3154
3155
    // "Click-jacking" defense (STR #4492)...
3156
0
    if (httpPrintf(http, "X-Frame-Options: DENY\r\nContent-Security-Policy: frame-ancestors 'none'\r\n") < 1)
3157
0
    {
3158
0
      http->status = HTTP_STATUS_ERROR;
3159
0
      return (-1);
3160
0
    }
3161
0
  }
3162
3163
0
  if (httpWrite2(http, "\r\n", 2) < 2)
3164
0
  {
3165
0
    http->status = HTTP_STATUS_ERROR;
3166
0
    return (-1);
3167
0
  }
3168
3169
0
  if (httpFlushWrite(http) < 0)
3170
0
  {
3171
0
    http->status = HTTP_STATUS_ERROR;
3172
0
    return (-1);
3173
0
  }
3174
3175
0
  if (status == HTTP_STATUS_CONTINUE || status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3176
0
  {
3177
    // Restore the old data_encoding and data_length values...
3178
0
    http->data_encoding  = old_encoding;
3179
0
    http->data_remaining = old_remaining;
3180
3181
0
    if (old_remaining <= INT_MAX)
3182
0
      http->_data_remaining = (int)old_remaining;
3183
0
    else
3184
0
      http->_data_remaining = INT_MAX;
3185
0
  }
3186
0
  else if (http->state == HTTP_STATE_OPTIONS || http->state == HTTP_STATE_HEAD || http->state == HTTP_STATE_PUT || http->state == HTTP_STATE_TRACE || http->state == HTTP_STATE_CONNECT || http->state == HTTP_STATE_STATUS)
3187
0
  {
3188
0
    DEBUG_printf("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, was %s.", httpStateString(http->state));
3189
0
    http->state = HTTP_STATE_WAITING;
3190
0
  }
3191
0
  else
3192
0
  {
3193
    // Force data_encoding and data_length to be set according to the response  headers...
3194
0
    http_set_length(http);
3195
3196
0
    if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
3197
0
    {
3198
0
      DEBUG_printf("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, was %s.", httpStateString(http->state));
3199
0
      http->state = HTTP_STATE_WAITING;
3200
0
      return (0);
3201
0
    }
3202
3203
0
    if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
3204
0
      http->state ++;
3205
3206
    // Then start any content encoding...
3207
0
    DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
3208
0
    http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
3209
0
  }
3210
3211
0
  return (0);
3212
0
}
3213
3214
3215
//
3216
// 'http_add_field()' - Add a value for a HTTP field, appending if needed.
3217
//
3218
3219
static void
3220
http_add_field(http_t       *http,  // I - HTTP connection
3221
               http_field_t field,  // I - HTTP field
3222
               const char   *value, // I - Value string
3223
               int          append) // I - Append value?
3224
0
{
3225
0
  char    temp[1024],   // Temporary value string
3226
0
    combined[HTTP_MAX_VALUE];
3227
          // Combined value string
3228
0
  size_t  fieldlen,   // Length of existing value
3229
0
    valuelen,   // Length of value string
3230
0
    total;      // Total length of string
3231
3232
3233
0
  if (field == HTTP_FIELD_HOST)
3234
0
  {
3235
    // Special-case for Host: as we don't want a trailing "." on the hostname
3236
    // and need to bracket IPv6 numeric addresses.
3237
0
    char *ptr = strchr(value, ':');
3238
3239
0
    if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
3240
0
    {
3241
      // Bracket IPv6 numeric addresses...
3242
      //
3243
      // This is slightly inefficient (basically copying twice), but is an edge
3244
      // case and not worth optimizing...
3245
0
      snprintf(temp, sizeof(temp), "[%s]", value);
3246
0
      value = temp;
3247
0
    }
3248
0
    else if (*value)
3249
0
    {
3250
      // Check for a trailing dot on the hostname...
3251
0
      cupsCopyString(temp, value, sizeof(temp));
3252
0
      value = temp;
3253
0
      ptr   = temp + strlen(temp) - 1;
3254
3255
0
      if (*ptr == '.')
3256
0
  *ptr = '\0';
3257
0
    }
3258
0
  }
3259
3260
0
  if (append && field != HTTP_FIELD_ACCEPT_ENCODING && field != HTTP_FIELD_ACCEPT_LANGUAGE && field != HTTP_FIELD_ACCEPT_RANGES && field != HTTP_FIELD_ALLOW && field != HTTP_FIELD_LINK && field != HTTP_FIELD_TRANSFER_ENCODING && field != HTTP_FIELD_UPGRADE && field != HTTP_FIELD_WWW_AUTHENTICATE)
3261
0
    append = 0;
3262
3263
0
  if (!append && http->fields[field])
3264
0
  {
3265
0
    if (field >= HTTP_FIELD_ACCEPT_ENCODING || http->fields[field] != http->_fields[field])
3266
0
      free(http->fields[field]);
3267
3268
0
    http->fields[field] = NULL;
3269
0
  }
3270
3271
0
  valuelen = strlen(value);
3272
3273
0
  if (!valuelen)
3274
0
  {
3275
0
    if (field < HTTP_FIELD_ACCEPT_ENCODING)
3276
0
      http->_fields[field][0] = '\0';
3277
0
    return;
3278
0
  }
3279
3280
0
  if (http->fields[field])
3281
0
  {
3282
0
    fieldlen = strlen(http->fields[field]);
3283
0
    total    = fieldlen + 2 + valuelen;
3284
0
  }
3285
0
  else
3286
0
  {
3287
0
    fieldlen = 0;
3288
0
    total    = valuelen;
3289
0
  }
3290
3291
0
  if (total < HTTP_MAX_VALUE && field < HTTP_FIELD_ACCEPT_ENCODING)
3292
0
  {
3293
    // Copy short values to legacy char arrays (maintained for binary
3294
    // compatibility with CUPS 1.2.x and earlier applications...)
3295
0
    if (fieldlen)
3296
0
    {
3297
0
      snprintf(combined, sizeof(combined), "%s, %s", http->_fields[field], value);
3298
0
      value = combined;
3299
0
    }
3300
3301
0
    cupsCopyString(http->_fields[field], value, sizeof(http->_fields[field]));
3302
0
    http->fields[field] = http->_fields[field];
3303
0
  }
3304
0
  else if (fieldlen)
3305
0
  {
3306
    // Expand the field value...
3307
0
    char *mcombined;      // New value string
3308
3309
0
    if (field < HTTP_FIELD_ACCEPT_ENCODING && http->fields[field] == http->_fields[field])
3310
0
    {
3311
0
      if ((mcombined = malloc(total + 1)) != NULL)
3312
0
      {
3313
0
  http->fields[field] = mcombined;
3314
0
  snprintf(mcombined, total + 1, "%s, %s", http->_fields[field], value);
3315
0
      }
3316
0
    }
3317
0
    else if ((mcombined = realloc(http->fields[field], total + 1)) != NULL)
3318
0
    {
3319
0
      http->fields[field] = mcombined;
3320
0
      cupsConcatString(mcombined, ", ", total + 1);
3321
0
      cupsConcatString(mcombined, value, total + 1);
3322
0
    }
3323
0
  }
3324
0
  else
3325
0
  {
3326
    // Allocate the field value...
3327
0
    http->fields[field] = strdup(value);
3328
0
  }
3329
3330
0
  if (field == HTTP_FIELD_CONTENT_ENCODING && http->data_encoding != HTTP_ENCODING_FIELDS)
3331
0
  {
3332
0
    DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
3333
0
    http_content_coding_start(http, value);
3334
0
  }
3335
0
}
3336
3337
3338
//
3339
// 'http_content_coding_finish()' - Finish doing any content encoding.
3340
//
3341
3342
static void
3343
http_content_coding_finish(
3344
    http_t *http)     // I - HTTP connection
3345
0
{
3346
0
  int   zerr;     // Compression status
3347
0
  Byte    dummy[1];   // Dummy read buffer
3348
0
  size_t  bytes;      // Number of bytes to write
3349
3350
3351
0
  DEBUG_printf("http_content_coding_finish(http=%p)", (void *)http);
3352
0
  DEBUG_printf("1http_content_coding_finishing: http->coding=%d", http->coding);
3353
3354
0
  switch (http->coding)
3355
0
  {
3356
0
    case _HTTP_CODING_DEFLATE :
3357
0
    case _HTTP_CODING_GZIP :
3358
0
        ((z_stream *)http->stream)->next_in  = dummy;
3359
0
        ((z_stream *)http->stream)->avail_in = 0;
3360
3361
0
        do
3362
0
        {
3363
0
          zerr  = deflate((z_stream *)http->stream, Z_FINISH);
3364
0
    bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
3365
3366
0
          if (bytes > 0)
3367
0
    {
3368
0
      DEBUG_printf("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes);
3369
3370
0
      if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3371
0
        http_write_chunk(http, (char *)http->sbuffer, bytes);
3372
0
      else
3373
0
        http_write(http, (char *)http->sbuffer, bytes);
3374
0
          }
3375
3376
0
          ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
3377
0
          ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3378
0
  }
3379
0
        while (zerr == Z_OK);
3380
3381
0
        deflateEnd((z_stream *)http->stream);
3382
3383
0
        free(http->sbuffer);
3384
0
        free(http->stream);
3385
3386
0
        http->sbuffer = NULL;
3387
0
        http->stream  = NULL;
3388
3389
0
        if (http->wused)
3390
0
          httpFlushWrite(http);
3391
0
        break;
3392
3393
0
    case _HTTP_CODING_INFLATE :
3394
0
    case _HTTP_CODING_GUNZIP :
3395
0
        inflateEnd((z_stream *)http->stream);
3396
3397
0
        free(http->sbuffer);
3398
0
        free(http->stream);
3399
3400
0
        http->sbuffer = NULL;
3401
0
        http->stream  = NULL;
3402
0
        break;
3403
3404
0
    default :
3405
0
        break;
3406
0
  }
3407
3408
0
  http->coding = _HTTP_CODING_IDENTITY;
3409
0
}
3410
3411
3412
//
3413
// 'http_content_coding_start()' - Start doing content encoding.
3414
//
3415
3416
static void
3417
http_content_coding_start(
3418
    http_t     *http,     // I - HTTP connection
3419
    const char *value)      // I - Value of Content-Encoding
3420
0
{
3421
0
  int     zerr;   // Error/status
3422
0
  _http_coding_t  coding;   // Content coding value
3423
3424
3425
0
  DEBUG_printf("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value);
3426
3427
0
  if (http->coding != _HTTP_CODING_IDENTITY)
3428
0
  {
3429
0
    DEBUG_printf("1http_content_coding_start: http->coding already %d.", http->coding);
3430
0
    return;
3431
0
  }
3432
0
  else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
3433
0
  {
3434
0
    if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND)
3435
0
    {
3436
0
      coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP;
3437
0
    }
3438
0
    else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV)
3439
0
    {
3440
0
      coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP;
3441
0
    }
3442
0
    else
3443
0
    {
3444
0
      DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3445
0
      return;
3446
0
    }
3447
0
  }
3448
0
  else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
3449
0
  {
3450
0
    if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND)
3451
0
    {
3452
0
      coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE;
3453
0
    }
3454
0
    else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV)
3455
0
    {
3456
0
      coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE;
3457
0
    }
3458
0
    else
3459
0
    {
3460
0
      DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3461
0
      return;
3462
0
    }
3463
0
  }
3464
0
  else
3465
0
  {
3466
0
    DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3467
0
    return;
3468
0
  }
3469
3470
0
  switch (coding)
3471
0
  {
3472
0
    case _HTTP_CODING_DEFLATE :
3473
0
    case _HTTP_CODING_GZIP :
3474
0
        if (http->wused)
3475
0
          httpFlushWrite(http);
3476
3477
0
        if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3478
0
        {
3479
0
          http->status = HTTP_STATUS_ERROR;
3480
0
          http->error  = errno;
3481
0
          return;
3482
0
        }
3483
3484
        // Window size for compression is 11 bits - optimal based on PWG Raster
3485
        // sample files on pwg.org.  -11 is raw deflate, 27 is gzip, per ZLIB
3486
        // documentation.
3487
0
  if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
3488
0
  {
3489
0
          free(http->sbuffer);
3490
3491
0
          http->sbuffer = NULL;
3492
0
          http->status  = HTTP_STATUS_ERROR;
3493
0
          http->error   = errno;
3494
0
          return;
3495
0
  }
3496
3497
0
        if ((zerr = deflateInit2((z_stream *)http->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK)
3498
0
        {
3499
0
          free(http->sbuffer);
3500
0
          free(http->stream);
3501
3502
0
          http->sbuffer = NULL;
3503
0
          http->stream  = NULL;
3504
0
          http->status  = HTTP_STATUS_ERROR;
3505
0
          http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3506
0
          return;
3507
0
        }
3508
3509
0
  ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
3510
0
  ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3511
0
        break;
3512
3513
0
    case _HTTP_CODING_INFLATE :
3514
0
    case _HTTP_CODING_GUNZIP :
3515
0
        if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3516
0
        {
3517
0
          http->status = HTTP_STATUS_ERROR;
3518
0
          http->error  = errno;
3519
0
          return;
3520
0
        }
3521
3522
        // Window size for decompression is up to 15 bits (maximum supported).
3523
        // -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
3524
0
  if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
3525
0
  {
3526
0
          free(http->sbuffer);
3527
3528
0
          http->sbuffer = NULL;
3529
0
          http->status  = HTTP_STATUS_ERROR;
3530
0
          http->error   = errno;
3531
0
          return;
3532
0
  }
3533
3534
0
        if ((zerr = inflateInit2((z_stream *)http->stream, coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK)
3535
0
        {
3536
0
          free(http->sbuffer);
3537
0
          free(http->stream);
3538
3539
0
          http->sbuffer = NULL;
3540
0
          http->stream  = NULL;
3541
0
          http->status  = HTTP_STATUS_ERROR;
3542
0
          http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3543
0
          return;
3544
0
        }
3545
3546
0
        ((z_stream *)http->stream)->avail_in = 0;
3547
0
        ((z_stream *)http->stream)->next_in  = http->sbuffer;
3548
0
        break;
3549
3550
0
    default :
3551
0
        break;
3552
0
  }
3553
3554
0
  http->coding = coding;
3555
3556
0
  DEBUG_printf("1http_content_coding_start: http->coding now %d.", http->coding);
3557
0
}
3558
3559
3560
//
3561
// 'http_create()' - Create an unconnected HTTP connection.
3562
//
3563
3564
static http_t *       // O - HTTP connection
3565
http_create(
3566
    const char        *host,    // I - Hostname
3567
    int               port,   // I - Port number
3568
    http_addrlist_t   *addrlist,  // I - Address list or `NULL`
3569
    int               family,   // I - Address family or AF_UNSPEC
3570
    http_encryption_t encryption, // I - Encryption to use
3571
    int               blocking,   // I - 1 for blocking mode
3572
    _http_mode_t      mode)   // I - _HTTP_MODE_CLIENT or _SERVER
3573
0
{
3574
0
  http_t  *http;      // New HTTP connection
3575
0
  char    service[255];   // Service name
3576
0
  http_addrlist_t *myaddrlist = NULL; // My address list
3577
3578
3579
0
  DEBUG_printf("4http_create(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, mode=%d)", host, port, (void *)addrlist, family, encryption, blocking, mode);
3580
3581
0
  if (!host && mode == _HTTP_MODE_CLIENT)
3582
0
    return (NULL);
3583
3584
0
  httpInitialize();
3585
3586
  // Lookup the host...
3587
0
  if (addrlist)
3588
0
  {
3589
0
    myaddrlist = httpAddrCopyList(addrlist);
3590
0
  }
3591
0
  else
3592
0
  {
3593
0
    snprintf(service, sizeof(service), "%d", port);
3594
3595
0
    myaddrlist = httpAddrGetList(host, family, service);
3596
0
  }
3597
3598
0
  if (!myaddrlist)
3599
0
    return (NULL);
3600
3601
  // Allocate memory for the structure...
3602
0
  if ((http = calloc(1, sizeof(http_t))) == NULL)
3603
0
  {
3604
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
3605
0
    httpAddrFreeList(myaddrlist);
3606
0
    return (NULL);
3607
0
  }
3608
3609
  // Initialize the HTTP data...
3610
0
  http->mode     = mode;
3611
0
  http->activity = time(NULL);
3612
0
  http->addrlist = myaddrlist;
3613
0
  http->blocking = blocking;
3614
0
  http->fd       = -1;
3615
#ifdef HAVE_GSSAPI
3616
  http->gssctx   = GSS_C_NO_CONTEXT;
3617
  http->gssname  = GSS_C_NO_NAME;
3618
#endif // HAVE_GSSAPI
3619
0
  http->status   = HTTP_STATUS_CONTINUE;
3620
0
  http->version  = HTTP_VERSION_1_1;
3621
3622
0
  if (host)
3623
0
    cupsCopyString(http->hostname, host, sizeof(http->hostname));
3624
3625
0
  if (port == 443)     // Always use encryption for https
3626
0
    http->encryption = HTTP_ENCRYPTION_ALWAYS;
3627
0
  else
3628
0
    http->encryption = encryption;
3629
3630
0
  http_set_wait(http);
3631
3632
  // Return the new structure...
3633
0
  return (http);
3634
0
}
3635
3636
3637
#ifdef DEBUG
3638
//
3639
// 'http_debug_hex()' - Do a hex dump of a buffer.
3640
//
3641
3642
static void
3643
http_debug_hex(const char *prefix,  // I - Prefix for line
3644
               const char *buffer,  // I - Buffer to dump
3645
               int        bytes)  // I - Bytes to dump
3646
{
3647
  int i, j,       // Looping vars
3648
  ch;       // Current character
3649
  char  line[255],      // Line buffer
3650
  *start,       // Start of line after prefix
3651
  *ptr;       // Pointer into line
3652
3653
3654
  if (_cups_debug_fd < 0 || _cups_debug_level < 6)
3655
    return;
3656
3657
  DEBUG_printf("9%s: %d bytes:", prefix, bytes);
3658
3659
  snprintf(line, sizeof(line), "9%s: ", prefix);
3660
  start = line + strlen(line);
3661
3662
  for (i = 0; i < bytes; i += 16)
3663
  {
3664
    for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
3665
      snprintf(ptr, 3, "%02X", buffer[i + j] & 255);
3666
3667
    while (j < 16)
3668
    {
3669
      memcpy(ptr, "  ", 3);
3670
      ptr += 2;
3671
      j ++;
3672
    }
3673
3674
    memcpy(ptr, "  ", 3);
3675
    ptr += 2;
3676
3677
    for (j = 0; j < 16 && (i + j) < bytes; j ++)
3678
    {
3679
      ch = buffer[i + j] & 255;
3680
3681
      if (ch < ' ' || ch >= 127)
3682
  ch = '.';
3683
3684
      *ptr++ = (char)ch;
3685
    }
3686
3687
    *ptr = '\0';
3688
    DEBUG_puts(line);
3689
  }
3690
}
3691
#endif // DEBUG
3692
3693
3694
//
3695
// 'http_read()' - Read a buffer from a HTTP connection.
3696
//
3697
// This function does the low-level read from the socket, retrying and timing
3698
// out as needed.
3699
//
3700
3701
static ssize_t        // O - Number of bytes read or -1 on error
3702
http_read(http_t *http,     // I - HTTP connection
3703
          char   *buffer,   // I - Buffer
3704
          size_t length)    // I - Maximum bytes to read
3705
0
{
3706
0
  ssize_t bytes;      // Bytes read
3707
3708
3709
0
  DEBUG_printf("7http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length);
3710
3711
0
  if (!http->blocking || http->timeout_value > 0.0)
3712
0
  {
3713
0
    while (!httpWait(http, http->wait_value))
3714
0
    {
3715
0
      if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
3716
0
  continue;
3717
3718
0
      DEBUG_puts("8http_read: Timeout.");
3719
0
      return (0);
3720
0
    }
3721
0
  }
3722
3723
0
  DEBUG_printf("8http_read: Reading %d bytes into buffer.", (int)length);
3724
3725
0
  do
3726
0
  {
3727
0
    if (http->tls)
3728
0
      bytes = _httpTLSRead(http, buffer, (int)length);
3729
0
    else
3730
0
      bytes = recv(http->fd, buffer, length, 0);
3731
3732
0
    if (bytes < 0)
3733
0
    {
3734
#ifdef _WIN32
3735
      if (WSAGetLastError() != WSAEINTR)
3736
      {
3737
  http->error = WSAGetLastError();
3738
  return (-1);
3739
      }
3740
      else if (WSAGetLastError() == WSAEWOULDBLOCK)
3741
      {
3742
  if (!http->timeout_cb ||
3743
      !(*http->timeout_cb)(http, http->timeout_data))
3744
  {
3745
    http->error = WSAEWOULDBLOCK;
3746
    return (-1);
3747
  }
3748
      }
3749
#else
3750
0
      DEBUG_printf("8http_read: %s", strerror(errno));
3751
3752
0
      if (errno == EWOULDBLOCK || errno == EAGAIN)
3753
0
      {
3754
0
  if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
3755
0
  {
3756
0
    http->error = errno;
3757
0
    return (-1);
3758
0
  }
3759
0
  else if (!http->timeout_cb && errno != EAGAIN)
3760
0
  {
3761
0
    http->error = errno;
3762
0
    return (-1);
3763
0
  }
3764
0
      }
3765
0
      else if (errno != EINTR)
3766
0
      {
3767
0
  http->error = errno;
3768
0
  return (-1);
3769
0
      }
3770
0
#endif // _WIN32
3771
0
    }
3772
0
  }
3773
0
  while (bytes < 0);
3774
3775
0
  DEBUG_printf("8http_read: Read " CUPS_LLFMT " bytes into buffer.", CUPS_LLCAST bytes);
3776
#ifdef DEBUG
3777
  if (bytes > 0)
3778
  {
3779
    http_debug_hex("http_read", buffer, (int)bytes);
3780
  }
3781
  else
3782
#endif // DEBUG
3783
0
  if (bytes == 0)
3784
0
  {
3785
0
    http->error = EPIPE;
3786
0
    return (0);
3787
0
  }
3788
3789
0
  return (bytes);
3790
0
}
3791
3792
3793
//
3794
// 'http_read_buffered()' - Do a buffered read from a HTTP connection.
3795
//
3796
// This function reads data from the HTTP buffer or from the socket, as needed.
3797
//
3798
3799
static ssize_t        // O - Number of bytes read or -1 on error
3800
http_read_buffered(http_t *http,  // I - HTTP connection
3801
                   char   *buffer,  // I - Buffer
3802
                   size_t length) // I - Maximum bytes to read
3803
0
{
3804
0
  ssize_t bytes;      // Bytes read
3805
3806
3807
0
  DEBUG_printf("7http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used);
3808
3809
0
  if (http->used > 0)
3810
0
  {
3811
0
    if (length > (size_t)http->used)
3812
0
      bytes = (ssize_t)http->used;
3813
0
    else
3814
0
      bytes = (ssize_t)length;
3815
3816
0
    DEBUG_printf("8http_read: Grabbing %d bytes from input buffer.", (int)bytes);
3817
3818
0
    memcpy(buffer, http->buffer, (size_t)bytes);
3819
0
    http->used -= (int)bytes;
3820
3821
0
    if (http->used > 0)
3822
0
      memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
3823
0
  }
3824
0
  else
3825
0
  {
3826
0
    bytes = http_read(http, buffer, length);
3827
0
  }
3828
3829
0
  return (bytes);
3830
0
}
3831
3832
3833
//
3834
// 'http_read_chunk()' - Read a chunk from a HTTP connection.
3835
//
3836
// This function reads and validates the chunk length, then does a buffered read
3837
// returning the number of bytes placed in the buffer.
3838
//
3839
3840
static ssize_t        // O - Number of bytes read or -1 on error
3841
http_read_chunk(http_t *http,   // I - HTTP connection
3842
    char   *buffer,   // I - Buffer
3843
    size_t length)    // I - Maximum bytes to read
3844
0
{
3845
0
  DEBUG_printf("7http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length);
3846
3847
0
  if (http->data_remaining <= 0)
3848
0
  {
3849
0
    char  len[32];    // Length string
3850
3851
0
    if (!httpGets2(http, len, sizeof(len)))
3852
0
    {
3853
0
      DEBUG_puts("8http_read_chunk: Could not get chunk length.");
3854
0
      return (0);
3855
0
    }
3856
3857
0
    if (!len[0])
3858
0
    {
3859
0
      DEBUG_puts("8http_read_chunk: Blank chunk length, trying again...");
3860
0
      if (!httpGets2(http, len, sizeof(len)))
3861
0
      {
3862
0
  DEBUG_puts("8http_read_chunk: Could not get chunk length.");
3863
0
  return (0);
3864
0
      }
3865
0
    }
3866
3867
0
    http->data_remaining = strtoll(len, NULL, 16);
3868
3869
0
    if (http->data_remaining < 0)
3870
0
    {
3871
0
      DEBUG_printf("8http_read_chunk: Negative chunk length \"%s\" (" CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining);
3872
0
      return (0);
3873
0
    }
3874
3875
0
    DEBUG_printf("8http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining);
3876
3877
0
    if (http->data_remaining == 0)
3878
0
    {
3879
      // 0-length chunk, grab trailing blank line...
3880
0
      httpGets2(http, len, sizeof(len));
3881
0
    }
3882
0
  }
3883
3884
0
  DEBUG_printf("8http_read_chunk: data_remaining=" CUPS_LLFMT, CUPS_LLCAST http->data_remaining);
3885
3886
0
  if (http->data_remaining <= 0)
3887
0
    return (0);
3888
0
  else if (length > (size_t)http->data_remaining)
3889
0
    length = (size_t)http->data_remaining;
3890
3891
0
  return (http_read_buffered(http, buffer, length));
3892
0
}
3893
3894
3895
//
3896
// 'http_send()' - Send a request with all fields and the trailing blank line.
3897
//
3898
3899
static bool       // O - `true` on success, `false` on error
3900
http_send(http_t       *http,   // I - HTTP connection
3901
          http_state_t request,   // I - Request code
3902
    const char   *uri)    // I - URI
3903
0
{
3904
0
  int   i;      // Looping var
3905
0
  char    buf[1024];    // Encoded URI buffer
3906
0
  const char  *value;     // Field value
3907
0
  static const char * const codes[] = // Request code strings
3908
0
    {
3909
0
      NULL,
3910
0
      "OPTIONS",
3911
0
      "GET",
3912
0
      NULL,
3913
0
      "HEAD",
3914
0
      "POST",
3915
0
      NULL,
3916
0
      NULL,
3917
0
      "PUT",
3918
0
      NULL,
3919
0
      "DELETE",
3920
0
      "TRACE",
3921
0
      "CLOSE",
3922
0
      NULL,
3923
0
      NULL
3924
0
    };
3925
3926
3927
0
  DEBUG_printf("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri);
3928
3929
0
  if (http == NULL || uri == NULL)
3930
0
    return (false);
3931
3932
  // Set the User-Agent field if it isn't already...
3933
0
  if (!http->fields[HTTP_FIELD_USER_AGENT])
3934
0
  {
3935
0
    if (http->default_fields[HTTP_FIELD_USER_AGENT])
3936
0
      httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_fields[HTTP_FIELD_USER_AGENT]);
3937
0
    else
3938
0
      httpSetField(http, HTTP_FIELD_USER_AGENT, cupsGetUserAgent());
3939
0
  }
3940
3941
  // Set the Accept-Encoding field if it isn't already...
3942
0
  if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING] && http->default_fields[HTTP_FIELD_ACCEPT_ENCODING])
3943
0
    httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING]);
3944
3945
  // Encode the URI as needed...
3946
0
  _httpEncodeURI(buf, uri, sizeof(buf));
3947
3948
  // See if we had an error the last time around; if so, reconnect...
3949
0
  if (http->fd < 0 || http->status == HTTP_STATUS_ERROR || http->status >= HTTP_STATUS_BAD_REQUEST)
3950
0
  {
3951
0
    DEBUG_printf("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d", http->fd, http->status, http->tls_upgrade);
3952
3953
0
    if (httpReconnect2(http, 30000, NULL))
3954
0
      return (false);
3955
0
  }
3956
3957
  // Flush any written data that is pending...
3958
0
  if (http->wused)
3959
0
  {
3960
0
    if (httpFlushWrite(http) < 0)
3961
0
    {
3962
0
      if (httpReconnect2(http, 30000, NULL))
3963
0
        return (false);
3964
0
    }
3965
0
  }
3966
3967
  // Send the request header...
3968
0
  http->state         = request;
3969
0
  http->data_encoding = HTTP_ENCODING_FIELDS;
3970
3971
0
  if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
3972
0
    http->state ++;
3973
3974
0
  http->status = HTTP_STATUS_CONTINUE;
3975
3976
0
  if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
3977
0
  {
3978
0
    httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3979
0
    httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
3980
0
  }
3981
3982
0
  if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
3983
0
  {
3984
0
    http->status = HTTP_STATUS_ERROR;
3985
0
    return (false);
3986
0
  }
3987
3988
0
  for (i = 0; i < HTTP_FIELD_MAX; i ++)
3989
0
  {
3990
0
    if ((value = httpGetField(http, i)) != NULL && *value)
3991
0
    {
3992
0
      DEBUG_printf("5http_send: %s: %s", http_fields[i], value);
3993
3994
0
      if (i == HTTP_FIELD_HOST)
3995
0
      {
3996
        // Issue #185: Use "localhost" for the loopback addresses to work
3997
        // around an Avahi bug...
3998
0
        if (httpAddrLocalhost(http->hostaddr))
3999
0
          value = "localhost";
4000
4001
0
  if (httpPrintf(http, "Host: %s:%d\r\n", value, httpAddrGetPort(http->hostaddr)) < 1)
4002
0
  {
4003
0
    http->status = HTTP_STATUS_ERROR;
4004
0
    return (false);
4005
0
  }
4006
0
      }
4007
0
      else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
4008
0
      {
4009
0
  http->status = HTTP_STATUS_ERROR;
4010
0
  return (false);
4011
0
      }
4012
0
    }
4013
0
  }
4014
4015
0
  if (http->cookie)
4016
0
  {
4017
0
    if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
4018
0
    {
4019
0
      http->status = HTTP_STATUS_ERROR;
4020
0
      return (false);
4021
0
    }
4022
0
  }
4023
4024
0
  DEBUG_printf("5http_send: expect=%d, mode=%d, state=%d", http->expect, http->mode, http->state);
4025
4026
0
  if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT && (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV))
4027
0
  {
4028
0
    if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
4029
0
    {
4030
0
      http->status = HTTP_STATUS_ERROR;
4031
0
      return (false);
4032
0
    }
4033
0
  }
4034
4035
0
  if (httpPrintf(http, "\r\n") < 1)
4036
0
  {
4037
0
    http->status = HTTP_STATUS_ERROR;
4038
0
    return (false);
4039
0
  }
4040
4041
0
  if (httpFlushWrite(http) < 0)
4042
0
    return (false);
4043
4044
0
  http_set_length(http);
4045
0
  httpClearFields(http);
4046
4047
  // The Kerberos and AuthRef authentication strings can only be used once...
4048
0
  if (http->fields[HTTP_FIELD_AUTHORIZATION] && http->authstring && (!strncmp(http->authstring, "Negotiate", 9) || !strncmp(http->authstring, "AuthRef", 7)))
4049
0
  {
4050
0
    http->_authstring[0] = '\0';
4051
4052
0
    if (http->authstring != http->_authstring)
4053
0
      free(http->authstring);
4054
4055
0
    http->authstring = http->_authstring;
4056
0
  }
4057
4058
0
  return (true);
4059
0
}
4060
4061
4062
//
4063
// 'http_set_length()' - Set the data_encoding and data_remaining values.
4064
//
4065
4066
static off_t        // O - Remainder or -1 on error
4067
http_set_length(http_t *http)   // I - Connection
4068
0
{
4069
0
  off_t remaining;      // Remainder
4070
4071
4072
0
  DEBUG_printf("4http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state));
4073
4074
0
  if ((remaining = httpGetLength2(http)) >= 0)
4075
0
  {
4076
0
    if (http->mode == _HTTP_MODE_SERVER && http->state != HTTP_STATE_GET_SEND && http->state != HTTP_STATE_PUT && http->state != HTTP_STATE_POST && http->state != HTTP_STATE_POST_SEND)
4077
0
    {
4078
0
      DEBUG_puts("5http_set_length: Not setting data_encoding/remaining.");
4079
0
      return (remaining);
4080
0
    }
4081
4082
0
    if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_TRANSFER_ENCODING), "chunked"))
4083
0
    {
4084
0
      DEBUG_puts("5http_set_length: Setting data_encoding to HTTP_ENCODING_CHUNKED.");
4085
0
      http->data_encoding = HTTP_ENCODING_CHUNKED;
4086
0
    }
4087
0
    else
4088
0
    {
4089
0
      DEBUG_puts("5http_set_length: Setting data_encoding to HTTP_ENCODING_LENGTH.");
4090
0
      http->data_encoding = HTTP_ENCODING_LENGTH;
4091
0
    }
4092
4093
0
    DEBUG_printf("5http_set_length: Setting data_remaining to " CUPS_LLFMT ".", CUPS_LLCAST remaining);
4094
0
    http->data_remaining = remaining;
4095
4096
0
    if (remaining <= INT_MAX)
4097
0
      http->_data_remaining = (int)remaining;
4098
0
    else
4099
0
      http->_data_remaining = INT_MAX;
4100
0
  }
4101
4102
0
  return (remaining);
4103
0
}
4104
4105
4106
//
4107
// 'http_set_timeout()' - Set the socket timeout values.
4108
//
4109
4110
static void
4111
http_set_timeout(int    fd,   // I - File descriptor
4112
                 double timeout)  // I - Timeout in seconds
4113
0
{
4114
#ifdef _WIN32
4115
  DWORD tv = (DWORD)(timeout * 1000);
4116
              // Timeout in milliseconds
4117
4118
  setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4119
  setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4120
4121
#else
4122
0
  struct timeval tv;      // Timeout in secs and usecs
4123
4124
0
  tv.tv_sec  = (int)timeout;
4125
0
  tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
4126
4127
0
  setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4128
0
  setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4129
0
#endif // _WIN32
4130
0
}
4131
4132
4133
//
4134
// 'http_set_wait()' - Set the default wait value for reads.
4135
//
4136
4137
static void
4138
http_set_wait(http_t *http)   // I - HTTP connection
4139
0
{
4140
0
  if (http->blocking)
4141
0
  {
4142
0
    http->wait_value = (int)(http->timeout_value * 1000);
4143
4144
0
    if (http->wait_value <= 0)
4145
0
      http->wait_value = 60000;
4146
0
  }
4147
0
  else
4148
0
  {
4149
0
    http->wait_value = 10000;
4150
0
  }
4151
0
}
4152
4153
4154
//
4155
// 'http_tls_upgrade()' - Force upgrade to TLS encryption.
4156
//
4157
4158
static bool       // O - `true` on success, `false` on error
4159
http_tls_upgrade(http_t *http)    // I - HTTP connection
4160
0
{
4161
0
  int   ret;      // Return value
4162
0
  http_t  myhttp;     // Local copy of HTTP data
4163
4164
4165
0
  DEBUG_printf("4http_tls_upgrade(%p)", (void *)http);
4166
4167
  // Flush the connection to make sure any previous "Upgrade" message
4168
  // has been read.
4169
0
  httpFlush(http);
4170
4171
  // Copy the HTTP data to a local variable so we can do the OPTIONS
4172
  // request without interfering with the existing request data...
4173
0
  memcpy(&myhttp, http, sizeof(myhttp));
4174
4175
  // Send an OPTIONS request to the server, requiring TLS
4176
  // encryption on the link...
4177
0
  http->tls_upgrade = 1;
4178
0
  memset(http->fields, 0, sizeof(http->fields));
4179
0
  http->expect = (http_status_t)0;
4180
4181
0
  if (http->hostname[0] == '/')
4182
0
    httpSetField(http, HTTP_FIELD_HOST, "localhost");
4183
0
  else
4184
0
    httpSetField(http, HTTP_FIELD_HOST, http->hostname);
4185
4186
0
  httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
4187
0
  httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.3,TLS/1.2,TLS/1.1,TLS/1.0");
4188
4189
0
  if ((ret = httpOptions(http, "*")) == 0)
4190
0
  {
4191
    // Wait for the secure connection...
4192
0
    while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
4193
0
  }
4194
4195
  // Restore the HTTP request data...
4196
0
  httpClearFields(http);
4197
0
  memcpy(http->_fields, myhttp._fields, sizeof(http->_fields));
4198
0
  memcpy(http->fields, myhttp.fields, sizeof(http->fields));
4199
4200
0
  http->data_encoding   = myhttp.data_encoding;
4201
0
  http->data_remaining  = myhttp.data_remaining;
4202
0
  http->_data_remaining = myhttp._data_remaining;
4203
0
  http->expect          = myhttp.expect;
4204
0
  http->digest_tries    = myhttp.digest_tries;
4205
0
  http->tls_upgrade     = 0;
4206
4207
  // See if we actually went secure...
4208
0
  if (!http->tls)
4209
0
  {
4210
    // Server does not support HTTP upgrade...
4211
0
    DEBUG_puts("5http_tls_upgrade: Server does not support HTTP upgrade!");
4212
4213
0
    _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1);
4214
0
    httpAddrClose(NULL, http->fd);
4215
4216
0
    http->fd = -1;
4217
4218
0
    return (false);
4219
0
  }
4220
0
  else
4221
0
  {
4222
0
    return (ret == 0);
4223
0
  }
4224
0
}
4225
4226
4227
//
4228
// 'http_write()' - Write a buffer to a HTTP connection.
4229
//
4230
4231
static ssize_t        // O - Number of bytes written
4232
http_write(http_t     *http,    // I - HTTP connection
4233
           const char *buffer,    // I - Buffer for data
4234
     size_t     length)   // I - Number of bytes to write
4235
0
{
4236
0
  ssize_t tbytes,     // Total bytes sent
4237
0
    bytes;      // Bytes sent
4238
4239
4240
0
  DEBUG_printf("7http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length);
4241
0
  http->error = 0;
4242
0
  tbytes      = 0;
4243
4244
0
  while (length > 0)
4245
0
  {
4246
0
    DEBUG_printf("8http_write: About to write %d bytes.", (int)length);
4247
4248
0
    if (http->timeout_value > 0.0)
4249
0
    {
4250
0
      struct pollfd pfd;    // Polled file descriptor
4251
0
      int   nfds;   // Result from select()/poll()
4252
4253
0
      do
4254
0
      {
4255
0
  pfd.fd     = http->fd;
4256
0
  pfd.events = POLLOUT;
4257
4258
0
        do
4259
0
        {
4260
0
          nfds = poll(&pfd, 1, http->wait_value);
4261
0
        }
4262
#  ifdef _WIN32
4263
  while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
4264
#  else
4265
0
  while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
4266
0
#  endif // _WIN32
4267
4268
0
        if (nfds < 0)
4269
0
  {
4270
0
    http->error = errno;
4271
0
    return (-1);
4272
0
  }
4273
0
  else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)))
4274
0
  {
4275
#ifdef _WIN32
4276
    http->error = WSAEWOULDBLOCK;
4277
#else
4278
0
    http->error = EWOULDBLOCK;
4279
0
#endif // _WIN32
4280
0
    return (-1);
4281
0
  }
4282
0
      }
4283
0
      while (nfds <= 0);
4284
0
    }
4285
4286
0
    if (http->tls)
4287
0
      bytes = _httpTLSWrite(http, buffer, (int)length);
4288
0
    else
4289
0
      bytes = send(http->fd, buffer, length, 0);
4290
4291
0
    DEBUG_printf("8http_write: Write of " CUPS_LLFMT " bytes returned " CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes);
4292
4293
0
    if (bytes < 0)
4294
0
    {
4295
#ifdef _WIN32
4296
      if (WSAGetLastError() == WSAEINTR)
4297
      {
4298
        continue;
4299
      }
4300
      else if (WSAGetLastError() == WSAEWOULDBLOCK)
4301
      {
4302
        if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4303
          continue;
4304
4305
        http->error = WSAGetLastError();
4306
      }
4307
      else if (WSAGetLastError() != http->error && WSAGetLastError() != WSAECONNRESET)
4308
      {
4309
        http->error = WSAGetLastError();
4310
  continue;
4311
      }
4312
4313
#else
4314
0
      if (errno == EINTR)
4315
0
      {
4316
0
        continue;
4317
0
      }
4318
0
      else if (errno == EWOULDBLOCK || errno == EAGAIN)
4319
0
      {
4320
0
  if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4321
0
          continue;
4322
0
        else if (!http->timeout_cb && errno == EAGAIN)
4323
0
    continue;
4324
4325
0
        http->error = errno;
4326
0
      }
4327
0
      else if (errno != http->error && errno != ECONNRESET)
4328
0
      {
4329
0
        http->error = errno;
4330
0
  continue;
4331
0
      }
4332
0
#endif // _WIN32
4333
4334
0
      DEBUG_printf("8http_write: error writing data (%s).", strerror(http->error));
4335
4336
0
      return (-1);
4337
0
    }
4338
4339
0
    buffer += bytes;
4340
0
    tbytes += bytes;
4341
0
    length -= (size_t)bytes;
4342
0
  }
4343
4344
#ifdef DEBUG
4345
  http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
4346
#endif // DEBUG
4347
4348
0
  DEBUG_printf("8http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes);
4349
4350
0
  return (tbytes);
4351
0
}
4352
4353
4354
//
4355
// 'http_write_chunk()' - Write a chunked buffer.
4356
//
4357
4358
static ssize_t        // O - Number bytes written
4359
http_write_chunk(http_t     *http,  // I - HTTP connection
4360
                 const char *buffer,  // I - Buffer to write
4361
     size_t        length)  // I - Length of buffer
4362
0
{
4363
0
  char    header[16];   // Chunk header
4364
0
  ssize_t bytes;      // Bytes written
4365
4366
4367
0
  DEBUG_printf("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length);
4368
4369
  // Write the chunk header, data, and trailer.
4370
0
  snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
4371
0
  if (http_write(http, header, strlen(header)) < 0)
4372
0
  {
4373
0
    DEBUG_puts("8http_write_chunk: http_write of length failed.");
4374
0
    return (-1);
4375
0
  }
4376
4377
0
  if ((bytes = http_write(http, buffer, length)) < 0)
4378
0
  {
4379
0
    DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
4380
0
    return (-1);
4381
0
  }
4382
4383
0
  if (http_write(http, "\r\n", 2) < 0)
4384
0
  {
4385
0
    DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
4386
0
    return (-1);
4387
0
  }
4388
4389
0
  return (bytes);
4390
0
}