Coverage Report

Created: 2025-08-28 07:06

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