-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchttp.h
More file actions
1395 lines (1146 loc) · 42.4 KB
/
chttp.h
File metadata and controls
1395 lines (1146 loc) · 42.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef CHTTP_INCLUDED
#define CHTTP_INCLUDED
// cHTTP, an HTTP client and server library!
//
// This file was generated automatically. Do not modify directly.
//
// Refer to the end of this file for the license
////////////////////////////////////////////////////////////////////////////////////////
// src/includes.h
////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <time.h>
#include <limits.h>
#include <stdarg.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#ifdef HTTPS_ENABLED
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#endif
////////////////////////////////////////////////////////////////////////////////////////
// src/basic.h
////////////////////////////////////////////////////////////////////////////////////////
enum {
CHTTP_OK = 0,
// A generic error occurred
CHTTP_ERROR_UNSPECIFIED = -1,
// Out of memory
CHTTP_ERROR_OOM = -2,
// Invalid URL
CHTTP_ERROR_BADURL = -3,
// Parallel request limit reached
CHTTP_ERROR_REQLIMIT = -4,
// Invalid handle
CHTTP_ERROR_BADHANDLE = -5,
// TLS support not built-in
CHTTP_ERROR_NOTLS = -6,
};
// String type used throughout cHTTP.
typedef struct {
char *ptr;
int len;
} CHTTP_String;
// Compare two strings and return true iff they have
// the same contents.
bool chttp_streq(CHTTP_String s1, CHTTP_String s2);
// Compre two strings case-insensitively (uppercase and
// lowercase versions of a letter are considered the same)
// and return true iff they have the same contents.
bool chttp_streqcase(CHTTP_String s1, CHTTP_String s2);
// Remove spaces and tabs from the start and the end of
// a string. This doesn't change the original string and
// the new one references the contents of the original one.
CHTTP_String chttp_trim(CHTTP_String s);
// Print the contents of a byte string with the given prefix.
// This is primarily used for debugging purposes.
void print_bytes(CHTTP_String prefix, CHTTP_String src);
// TODO: comment
char *chttp_strerror(int code);
// Macro to simplify converting string literals to
// CHTTP_String.
//
// Instead of doing this:
//
// char *s = "some string";
//
// You do this:
//
// CHTTP_String s = CHTTP_STR("some string")
//
// This is a bit cumbersome, but better than null-terminated
// strings, having a pointer and length variable pairs whenever
// a function operates on a string. If this wasn't a library
// I would have done for
//
// #define S(X) ...
//
// But I don't want to cause collisions with user code.
#define CHTTP_STR(X) ((CHTTP_String) {(X), sizeof(X)-1})
// Returns the number of items of a static array.
#define CHTTP_COUNT(X) (int) (sizeof(X) / sizeof((X)[0]))
// Macro to unpack an CHTTP_String into its length and pointer components.
// Useful for passing CHTTP_String to printf-style functions with "%.*s" format.
// Example: printf("%.*s", CHTTP_UNPACK(str));
#define CHTTP_UNPACK(X) (X).len, (X).ptr
// TODO: comment
#define CHTTP_UNREACHABLE __builtin_trap()
////////////////////////////////////////////////////////////////////////////////////////
// src/parse.h
////////////////////////////////////////////////////////////////////////////////////////
#define CHTTP_MAX_HEADERS 32
typedef struct {
unsigned int data;
} CHTTP_IPv4;
typedef struct {
unsigned short data[8];
} CHTTP_IPv6;
typedef enum {
CHTTP_HOST_MODE_VOID = 0,
CHTTP_HOST_MODE_NAME,
CHTTP_HOST_MODE_IPV4,
CHTTP_HOST_MODE_IPV6,
} CHTTP_HostMode;
typedef struct {
CHTTP_HostMode mode;
CHTTP_String text;
union {
CHTTP_String name;
CHTTP_IPv4 ipv4;
CHTTP_IPv6 ipv6;
};
} CHTTP_Host;
typedef struct {
CHTTP_String userinfo;
CHTTP_Host host;
int port;
} CHTTP_Authority;
// ZII
typedef struct {
CHTTP_String scheme;
CHTTP_Authority authority;
CHTTP_String path;
CHTTP_String query;
CHTTP_String fragment;
} CHTTP_URL;
typedef enum {
CHTTP_METHOD_GET,
CHTTP_METHOD_HEAD,
CHTTP_METHOD_POST,
CHTTP_METHOD_PUT,
CHTTP_METHOD_DELETE,
CHTTP_METHOD_CONNECT,
CHTTP_METHOD_OPTIONS,
CHTTP_METHOD_TRACE,
CHTTP_METHOD_PATCH,
} CHTTP_Method;
typedef struct {
CHTTP_String name;
CHTTP_String value;
} CHTTP_Header;
typedef struct {
bool secure;
CHTTP_Method method;
CHTTP_URL url;
int minor;
int num_headers;
CHTTP_Header headers[CHTTP_MAX_HEADERS];
CHTTP_String body;
} CHTTP_Request;
typedef struct {
void* context;
int minor;
int status;
CHTTP_String reason;
int num_headers;
CHTTP_Header headers[CHTTP_MAX_HEADERS];
CHTTP_String body;
} CHTTP_Response;
int chttp_parse_ipv4 (char *src, int len, CHTTP_IPv4 *ipv4);
int chttp_parse_ipv6 (char *src, int len, CHTTP_IPv6 *ipv6);
int chttp_parse_url (char *src, int len, CHTTP_URL *url);
int chttp_parse_request (char *src, int len, CHTTP_Request *req);
int chttp_parse_response (char *src, int len, CHTTP_Response *res);
int chttp_find_header (CHTTP_Header *headers, int num_headers, CHTTP_String name);
CHTTP_String chttp_get_cookie (CHTTP_Request *req, CHTTP_String name);
CHTTP_String chttp_get_param (CHTTP_String body, CHTTP_String str, char *mem, int cap);
int chttp_get_param_i (CHTTP_String body, CHTTP_String str);
// Checks whether the request was meant for the host with the given
// domain an port. If port is -1, the default value of 80 is assumed.
bool chttp_match_host(CHTTP_Request *req, CHTTP_String domain, int port);
// Date and cookie types for Set-Cookie header parsing
typedef enum {
CHTTP_WEEKDAY_MON,
CHTTP_WEEKDAY_TUE,
CHTTP_WEEKDAY_WED,
CHTTP_WEEKDAY_THU,
CHTTP_WEEKDAY_FRI,
CHTTP_WEEKDAY_SAT,
CHTTP_WEEKDAY_SUN,
} CHTTP_WeekDay;
typedef enum {
CHTTP_MONTH_JAN,
CHTTP_MONTH_FEB,
CHTTP_MONTH_MAR,
CHTTP_MONTH_APR,
CHTTP_MONTH_MAY,
CHTTP_MONTH_JUN,
CHTTP_MONTH_JUL,
CHTTP_MONTH_AUG,
CHTTP_MONTH_SEP,
CHTTP_MONTH_OCT,
CHTTP_MONTH_NOV,
CHTTP_MONTH_DEC,
} CHTTP_Month;
typedef struct {
CHTTP_WeekDay week_day;
int day;
CHTTP_Month month;
int year;
int hour;
int minute;
int second;
} CHTTP_Date;
typedef struct {
CHTTP_String name;
CHTTP_String value;
bool secure;
bool chttp_only;
bool have_date;
CHTTP_Date date;
bool have_max_age;
uint32_t max_age;
bool have_domain;
CHTTP_String domain;
bool have_path;
CHTTP_String path;
} CHTTP_SetCookie;
// Parses a Set-Cookie header value
// Returns 0 on success, -1 on error
int chttp_parse_set_cookie(CHTTP_String str, CHTTP_SetCookie *out);
////////////////////////////////////////////////////////////////////////////////////////
// src/time.h
////////////////////////////////////////////////////////////////////////////////////////
typedef uint64_t Time;
#define INVALID_TIME ((Time) UINT64_MAX-1)
Time get_current_time(void);
////////////////////////////////////////////////////////////////////////////////////////
// src/secure_context.h
////////////////////////////////////////////////////////////////////////////////////////
#ifndef SERVER_CERTIFICATE_LIMIT
// Maximum number of certificates that can be
// associated to a TLS server. This doesn't include
// the default certificate.
#define SERVER_CERTIFICATE_LIMIT 8
#endif
int global_secure_context_init(void);
int global_secure_context_free(void);
typedef struct {
#ifdef HTTPS_ENABLED
SSL_CTX *p;
#endif
} ClientSecureContext;
int client_secure_context_init(ClientSecureContext *ctx);
void client_secure_context_free(ClientSecureContext *ctx);
typedef struct {
#ifdef HTTPS_ENABLED
char domain[128];
SSL_CTX *ctx;
#endif
} ServerCertificate;
typedef struct {
#ifdef HTTPS_ENABLED
SSL_CTX *p;
int num_certs;
ServerCertificate certs[SERVER_CERTIFICATE_LIMIT];
#endif
} ServerSecureContext;
int server_secure_context_init(ServerSecureContext *ctx,
CHTTP_String cert_file, CHTTP_String key_file);
void server_secure_context_free(ServerSecureContext *ctx);
int server_secure_context_add_certificate(ServerSecureContext *ctx,
CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
////////////////////////////////////////////////////////////////////////////////////////
// src/socket.h
////////////////////////////////////////////////////////////////////////////////////////
// This file (and its relative .c file) implements an asynchronous TCP/TLS
// server and client abstraction.
//
// It introduces the concept of a "socket manager", which is a pool of
// connection sockets and a listener socket. The listener is managed
// internally, which means the manager automatically accepts sockets
// from it and adds them to the pool.
//
// If the listener is configured using the function:
//
// socket_manager_listen_tcp
//
// the resulting connections will not use TLS. If instead the listener
// is configured using:
//
// socket_manager_listen_tls
//
// the listener will use TLS. Note that both functions can be used on
// the same manager to allow both plaintext and encrypted connections.
// Users may enable zero listeners, in which case only outgoing
// connections are allowed (more on this later).
//
// Once the manager is set up, one can wait for events by following
// this pattern:
//
// struct pollfd polled[...];
// int num_polled = socket_manager_register_events(sm, polled, max_polled);
// poll(polled, num_polled, -1);
//
// #define MAX_EVENTS ...
// SocketEvent events[MAX_EVENTS];
// int num_events = socket_manager_translate_events(sm, events, MAX_EVENTS, polled, num_polled);
// for (int i = 0; i < num_events; i++) {
// ... Here call socket_recv, socket_send, socket_close, ...
// }
//
// Note that from the user's perspective, there is no difference
// between connections that use plain TCP and those that use TCP/TLS.
//
// Users can also establish outgoing connections by calling the
// function:
//
// socket_connect
//
// Which allows the creation of a connection towards an host given
// its domain, IPv4, IPv6, or an array of them. This can be done both
// for TCP and TCP/TLS connection. Note that users that only intend
// to establish outgoing connection may omit the configuration of
// listeners entirely.
#ifdef _WIN32
#define NATIVE_SOCKET SOCKET
#define NATIVE_SOCKET_INVALID INVALID_SOCKET
#define CLOSE_NATIVE_SOCKET closesocket
#else
#define NATIVE_SOCKET int
#define NATIVE_SOCKET_INVALID -1
#define CLOSE_NATIVE_SOCKET close
#endif
typedef uint32_t SocketHandle;
#define SOCKET_HANDLE_INVALID ((SocketHandle) 0)
typedef uint16_t Port;
typedef enum {
SOCKET_EVENT_READY,
SOCKET_EVENT_CREATION_TIMEOUT,
SOCKET_EVENT_RECV_TIMEOUT,
SOCKET_EVENT_DISCONNECT,
} SocketEventType;
typedef struct {
SocketEventType type;
SocketHandle handle;
void* user;
} SocketEvent;
// Internal use only
typedef enum {
// The Socket struct is unused
SOCKET_STATE_FREE,
// The state associated to a socket created
// by a connect operation that hasn't been
// processed yet.
SOCKET_STATE_PENDING,
// A connect() operation was started but is
// still pending.
SOCKET_STATE_CONNECTING,
// Outgoing connection was established, but
// a TLS handshake may need to be performed.
SOCKET_STATE_CONNECTED,
// Incoming connection was established, but
// a TLS handshake may need to be performed.
SOCKET_STATE_ACCEPTED,
// The connection was esablished, but the user
// wants to perform a read or write operation that
// would block.
SOCKET_STATE_ESTABLISHED_WAIT,
// The connection was established and it's possible
// to perform read or write operations on it without
// blocking.
SOCKET_STATE_ESTABLISHED_READY,
// The socket was marked to be closed.
SOCKET_STATE_SHUTDOWN,
// The current socket is was closed. The only
// valid thing to do here is free its resources.
SOCKET_STATE_DIED,
} SocketState;
typedef struct {
int refs;
char data[];
} RegisteredName;
// Internal use only
typedef struct {
union {
CHTTP_IPv4 ipv4;
CHTTP_IPv6 ipv6;
};
bool is_ipv4;
Port port;
#ifdef HTTPS_ENABLED
// When connecting to a peer using TLS, if the address
// was resolved from a registered name, that name is
// used to request the correct certificate once the TCP
// handshake is established, and therefore need to
// store it somewhere until that happens.
RegisteredName *name;
#endif
} AddressAndPort;
// Internal use only
typedef struct {
SocketState state;
// OS-specific socket type
NATIVE_SOCKET sock;
// Native socket events that need to be monitored
int events;
// If this is set, the raw socket handle shouldn't be monitored
bool silent;
// Generation counter to invalidate any SocketHandle
// referring to this socket when it is freed.
// Note that this counter may wrap but always skips
// the 0 value to ensure the 0 SocketHandle is always
// invalid.
uint16_t gen;
// User-provided context pointer
void *user;
Time creation_time;
Time last_recv_time;
Time recv_timeout;
Time creation_timeout;
// A single connect operation may involve
// trying to establish a connection towards
// one of a set of addresses.
int num_addr;
int next_addr;
union {
AddressAndPort addr; // When num_addr=1
AddressAndPort *addrs; // Dynamically allocated when num_addr>1
};
#ifdef HTTPS_ENABLED
ClientSecureContext *client_secure_context;
ServerSecureContext *server_secure_context;
SSL *ssl;
bool dont_verify_cert;
#endif
} Socket;
// Glorified array of sockets. This structure
// is private to the .c file associated to this
// header.
typedef struct {
// TODO: comment
Time recv_timeout;
Time creation_timeout;
// TCP listener sockets. The first is intended
// for plaintext, while the second is for TLS.
// The socket manager will accept and add new
// sockets to the pool automatically. Note that
// either may be unset. If both are unset, users
// can only create outgoing connections.
NATIVE_SOCKET plain_sock;
NATIVE_SOCKET secure_sock;
// Handles for the self-pipe trick necessary for
// other threads to wake up sockets blocked on
// poll().
NATIVE_SOCKET wait_sock;
NATIVE_SOCKET signal_sock;
// TLS contexts. One is used for outgoing connections
// (the client context) and one for incoming
// connections (server). If the secure_sock is
// set, the server context is initialized. If at
// least one connect was performed using TLS
// (and the flag is set), the client context is
// initialized.
bool at_least_one_secure_connect;
ClientSecureContext client_secure_context;
ServerSecureContext server_secure_context;
// If the socket manager needed to initialize some
// global state for its initialization, this flag
// will be set so that it will remember to cleanup
// that state during deinitialization.
bool global_cleanup;
// Array of sockets. Structs with state FREE
// are unused.
int num_used;
int max_used;
Socket *sockets;
} SocketManager;
// Instanciate a socket manager. Returns 0 on
// success and -1 on error.
int socket_manager_init(SocketManager *sm, Socket *socks,
int num_socks);
// Deinitialize a socket manager
void socket_manager_free(SocketManager *sm);
void socket_manager_set_creation_timeout(SocketManager *sm, int timeout);
void socket_manager_set_recv_timeout(SocketManager *sm, int timeout);
// Configure the socket manager to listen on
// the specified interface for TCP connections.
// Incoming connections will be automatically
// added to the internal pool. This function
// can only be used once per manager.
// Returns 0 on success, -1 on error.
int socket_manager_listen_tcp(SocketManager *sm,
CHTTP_String addr, Port port, int backlog,
bool reuse_addr);
// Same as the previous function, but incoming
// connections will be interpreted as TLS. You
// can only call this function once per manager,
// but you can call this and the plaintext variant
// on the same manager to accept both plaintext
// and secure connections.
// Returns 0 on success, -1 on error.
int socket_manager_listen_tls(SocketManager *sm,
CHTTP_String addr, Port port, int backlog,
bool reuse_addr, CHTTP_String cert_file,
CHTTP_String key_file);
// If the socket manager was configures to accept
// TLS connections, this adds additional certificates
// the client can use to verify the server's
// authenticity.
// Returns 0 on success, -1 on error.
int socket_manager_add_certificate(SocketManager *sm,
CHTTP_String domain, CHTTP_String cert_file, CHTTP_String key_file);
// When a thread is blocked on a poll() call for
// descriptors associated to this socket manager,
// other threads can call this function to wake
// up that blocked thread.
// Returns 0 on success, -1 on error.
int socket_manager_wakeup(SocketManager *sm);
typedef struct {
void **ptrs;
struct pollfd *polled;
int num_polled;
int timeout;
} EventRegister;
// Resets the event register with the list of descriptors
// the socket manager wants monitored.
void socket_manager_register_events(SocketManager *sm,
EventRegister *reg);
// After poll() is called on the previously registered
// pollfd array and the revents fields are set, this
// function processes those events to produce higher-level
// socket events. Returns the number of socket events
// written to the output array, or -1 on error.
//
// The maximum number of events this will write
// to the events array is equal to the numero of
// socket structs provided to the socket manager
// via the init function.
int socket_manager_translate_events(SocketManager *sm,
SocketEvent *events, EventRegister reg);
typedef enum {
CONNECT_TARGET_NAME,
CONNECT_TARGET_IPV4,
CONNECT_TARGET_IPV6,
} ConnectTargetType;
typedef struct {
ConnectTargetType type;
Port port;
union {
CHTTP_IPv4 ipv4;
CHTTP_IPv6 ipv6;
CHTTP_String name;
};
} ConnectTarget;
// Connect to one of the given targets. The socket
// manager will try to connecting to addresses until
// one succedes. If secure=true, the socket uses TLS.
// Returns 0 on success, -1 on error.
int socket_connect(SocketManager *sm, int num_targets,
ConnectTarget *targets, bool secure, bool dont_verify_cert,
void *user);
int socket_recv(SocketManager *sm, SocketHandle handle,
char *dst, int max);
int socket_send(SocketManager *sm, SocketHandle handle,
char *src, int len);
void socket_close(SocketManager *sm, SocketHandle handle);
// Returns -1 on error, 0 if the socket was accepted
// from the plaintext listener, or 1 if it was accepted
// by the secure listener.
bool socket_is_secure(SocketManager *sm, SocketHandle handle);
// Set the user pointer of a socket
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
// Returns true iff the socket is ready for reading or
// writing.
bool socket_ready(SocketManager *sm, SocketHandle handle);
// When a socket is marked as silent it will not generate events
void socket_silent(SocketManager *sm, SocketHandle handle, bool value);
////////////////////////////////////////////////////////////////////////////////////////
// src/byte_queue.h
////////////////////////////////////////////////////////////////////////////////////////
// This is the implementation of a byte queue useful
// for systems that need to process engs of bytes.
//
// It features sticky errors, a zero-copy interface,
// and a safe mechanism to patch previously written
// bytes.
//
// Only up to 4GB of data can be stored at once.
// Internal use only
enum {
BYTE_QUEUE_ERROR = 1 << 0,
BYTE_QUEUE_READ = 1 << 1,
BYTE_QUEUE_WRITE = 1 << 2,
};
typedef struct {
char *ptr;
size_t len;
} ByteView;
// Fields are for internal use only
typedef struct {
uint64_t curs;
char* data;
uint32_t head;
uint32_t size;
uint32_t used;
uint32_t limit;
char* read_target;
uint32_t read_target_size;
int flags;
} ByteQueue;
// Represents an offset inside the queue relative
// to the first byte ever appended to the queue,
// therefore consuming bytes from the queue does
// not invalidate this type of offset.
typedef uint64_t ByteQueueOffset;
// Initialize the queue with a given capacity limit.
// This is just a soft limit. The queue will allocate
// dynamically as needed up to this limit and won't
// grow further. When the limit is reached, chttp_queue_full
// returns true.
void byte_queue_init(ByteQueue *queue, uint32_t limit);
// Free resources associated to this queue
void byte_queue_free(ByteQueue *queue);
// Check whether an error occurred inside the queue
int byte_queue_error(ByteQueue *queue);
// Returns 1 if the queue has no bytes inside it,
// or 0 otherwise.
int byte_queue_empty(ByteQueue *queue);
// Returns 1 if the queue reached its limit, or 0
// otherwise.
int byte_queue_full(ByteQueue *queue);
// These two functions are to be used together.
// read_buf returns a view into the queue of the
// bytes that can be read from it. The caller can
// decide how many of those bytes can be removed
// by passing the count to the read_ack function.
// If an error occurred inside the queue, this
// function returns an empty view.
//
// Note that the calls to read_buf and read_ack
// may be far apart. Other operations won't interfere
// with the read. The only rule is you can't call
// read_buf multiple times before calling read_ack.
ByteView byte_queue_read_buf(ByteQueue *queue);
void byte_queue_read_ack(ByteQueue *queue, uint32_t num);
// Similar to the read_buf/read_ack functions,
// but write_buf returns a view of the unused
// memory inside the queue, and write_ack is
// used to tell the queue how many bytes were
// written into it. Note that to ensure there
// is a minimum amount of free space in the queue,
// the user needs to call byte_queue_setmincap.
// If an error occurred inside the queue, this
// function returns an empty view.
//
// Note that the calls to write_buf and write_ack
// may be far apart. Other operations won't interfere
// with the write (except for other byte_queue_write_*
// functions). The only rule is you can't call
// write_buf multiple times before calling write_ack.
ByteView byte_queue_write_buf(ByteQueue *queue);
void byte_queue_write_ack(ByteQueue *queue, uint32_t num);
// Sets the minimum capacity for the next write
// operation and returns 1 if the content of the
// queue was moved, else 0 is returned.
//
// You must not call this function while a write
// is pending. In other words, you must do this:
//
// byte_queue_write_setmincap(queue, mincap);
// dst = byte_queue_write_buf(queue, &cap);
// ...
// byte_queue_write_ack(num);
//
// And NOT this:
//
// dst = byte_queue_write_buf(queue);
// byte_queue_write_setmincap(queue, mincap); <-- BAD
// ...
// byte_queue_write_ack(num);
//
int byte_queue_write_setmincap(ByteQueue *queue, uint32_t mincap);
// Write some bytes to the queue. This is a
// short hand for write_buf/memcpy/write_ack
void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len);
// Write the result of the format into the queue
void byte_queue_write_fmt(ByteQueue *queue, const char *fmt, ...);
// Write the result of the format into the queue
void byte_queue_write_fmt2(ByteQueue *queue, const char *fmt,
va_list args);
// Returns the current offset inside the queue
ByteQueueOffset byte_queue_offset(ByteQueue *queue);
// Writes some bytes at the specified offset. It's
// the responsibility of the user to make sure that
// the offset still refers to content inside the queue.
void byte_queue_patch(ByteQueue *queue, ByteQueueOffset off, void *src, uint32_t len);
// Returns the number of bytes from the given offset
// to the end of the queue.
uint32_t byte_queue_size_from_offset(ByteQueue *queue, ByteQueueOffset off);
// Removes all bytes from the given offset to the the
// end of the queue.
void byte_queue_remove_from_offset(ByteQueue *queue, ByteQueueOffset offset);
////////////////////////////////////////////////////////////////////////////////////////
// src/cert.h
////////////////////////////////////////////////////////////////////////////////////////
// This is an utility to create self-signed certificates
// useful when testing HTTPS servers locally. This is only
// meant to be used by people starting out with a library
// and simplifying the zero to one phase.
//
// The C, O, and CN are respectively country name, organization name,
// and common name of the certificate. For instance:
//
// C="IT"
// O="My Organization"
// CN="my_website.com"
//
// The output is a certificate file in PEM format and a private
// key file with the key used to sign the certificate.
int chttp_create_test_certificate(CHTTP_String C, CHTTP_String O, CHTTP_String CN,
CHTTP_String cert_file, CHTTP_String key_file);
////////////////////////////////////////////////////////////////////////////////////////
// src/client.h
////////////////////////////////////////////////////////////////////////////////////////
#ifndef CHTTP_CLIENT_CAPACITY
// The maximum ammount of requests that can be performed
// in parallel.
#define CHTTP_CLIENT_CAPACITY (1<<7)
#endif
// Maximum number of descriptors the client will want
// to wait on. It's one per connection plus the wakeup
// self-pipe.
#define CHTTP_CLIENT_POLL_CAPACITY (CHTTP_CLIENT_CAPACITY+1)
#ifndef CHTTP_COOKIE_JAR_CAPACITY
// Maximum number of cookies that can be associated to a
// single client.
#define CHTTP_COOKIE_JAR_CAPACITY 128
#endif
typedef struct {
// Cookie name and value
CHTTP_String name;
CHTTP_String value;
// If the "exact_domain" is true, the cookie
// can only be sent to the exact domain referred
// to by "domain" (which is never empty). If
// "exact_domain" is false, then the cookie is
// compatible with subdomains.
bool exact_domain;
CHTTP_String domain;
// If "exact_path" is set, the cookie is only
// compatible with requests to paths that match
// "path" exactly. If "exact_path" is not set,
// then any path that starts with "path" is
// compatible with the cookie.
bool exact_path;
CHTTP_String path;
// This cookie can only be sent over HTTPS
bool secure;
} CHTTP_CookieJarEntry;
typedef struct {
int count;
CHTTP_CookieJarEntry items[CHTTP_COOKIE_JAR_CAPACITY];
} CHTTP_CookieJar;
typedef enum {
CHTTP_CLIENT_CONN_FREE,
CHTTP_CLIENT_CONN_WAIT_METHOD,
CHTTP_CLIENT_CONN_WAIT_URL,
CHTTP_CLIENT_CONN_WAIT_HEADER,
CHTTP_CLIENT_CONN_WAIT_BODY,
CHTTP_CLIENT_CONN_FLUSHING,
CHTTP_CLIENT_CONN_BUFFERING,
CHTTP_CLIENT_CONN_COMPLETE,
} CHTTP_ClientConnState;
// Fields of this struct are private
typedef struct CHTTP_Client CHTTP_Client;
typedef struct {
CHTTP_ClientConnState state;
// Handle to the socket
SocketHandle handle;
// Pointer back to the client
CHTTP_Client *client;
// Generation counter for request builder validation
uint16_t gen;
// Opaque pointer set by the user while building
// the request. It's returned alongside the result.
void *user;
// TODO: comment
bool trace_bytes;
// TODO: comment
bool dont_verify_cert;
// Allocated copy of the URL string
CHTTP_String url_buffer;
// Parsed URL for connection establishment
// All url.* pointers reference into url_buffer
CHTTP_URL url;
// Data received from the server
ByteQueue input;
// Data being sent to the server
ByteQueue output;
// If the request is COMPLETE, indicates
// whether it completed with an error (-1)
// or a success (0). If it was a success,
// the response field is valid.
int result;
// Parsed response once complete
CHTTP_Response response;
// This offset points to the first byte that comes
// after the string "Content-Length: ".
ByteQueueOffset content_length_value_offset;
// This one points to the first byte of the body.
// This allows calculating the length of the request
// content byte subtracting it from the offset reached
// when the request is marked as done.
ByteQueueOffset content_length_offset;
} CHTTP_ClientConn;
// Fields of this struct are private
struct CHTTP_Client {
// Size limit of the input and output buffer of each
// connection.
uint32_t input_buffer_limit;
uint32_t output_buffer_limit;
// List of cookies created during this session