Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

  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
/*
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __HTTP_H__
#define __HTTP_H__

#if defined(CONFIG_HTTPS)
#if defined(CONFIG_MBEDTLS)
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
#include "mbedtls/config.h"
#else
#include CONFIG_MBEDTLS_CFG_FILE
#endif /* CONFIG_MBEDTLS_CFG_FILE */

#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_time_t       time_t
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif /* MBEDTLS_PLATFORM_C */

#include <mbedtls/ssl_cookie.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/ssl.h>
#include <mbedtls/error.h>
#include <mbedtls/debug.h>
#endif /* CONFIG_MBEDTLS */
#endif /* CONFIG_HTTPS */

#define HTTP_CRLF "\r\n"

#if defined(CONFIG_HTTP_CLIENT)

#include <net/http_parser.h>
#include <net/net_context.h>

/* Is there more data to come */
enum http_final_call {
	HTTP_DATA_MORE = 0,
	HTTP_DATA_FINAL = 1,
};

#ifndef HTTP_PROTOCOL
#define HTTP_PROTOCOL	   "HTTP/1.1"
#endif

/* Some generic configuration options, these can be overriden if needed. */
#ifndef HTTP_STATUS_STR_SIZE
#define HTTP_STATUS_STR_SIZE	32
#endif

/* Default network activity timeout in seconds */
#define HTTP_NETWORK_TIMEOUT	K_SECONDS(20)

/* It seems enough to hold 'Content-Length' and its value */
#define HTTP_CONTENT_LEN_SIZE	48

/* Default HTTP Header Field values for HTTP Requests if using the
 * HTTP_HEADER_FIELDS define.
 */
#ifndef HTTP_ACCEPT
#define HTTP_ACCEPT		"text/plain"
#endif

#ifndef HTTP_ACCEPT_ENC
#define HTTP_ACCEPT_ENC		"identity"
#endif

#ifndef HTTP_ACCEPT_LANG
#define HTTP_ACCEPT_LANG	"en-US"
#endif

#ifndef HTTP_CONNECTION
#define HTTP_CONNECTION		"Close"
#endif

#ifndef HTTP_USER_AGENT
#define HTTP_USER_AGENT	"Zephyr-HTTP-Client/1.8"
#endif

/* This can be used in http_client_send_get_req() when supplying
 * extra_header_fields parameter.
 */
#ifndef HTTP_HEADER_FIELDS
#define HTTP_HEADER_FIELDS				     \
	"Accept: " HTTP_ACCEPT HTTP_CRLF		     \
	"Accept-Encoding: " HTTP_ACCEPT_ENC HTTP_CRLF	     \
	"Accept-Language: " HTTP_ACCEPT_LANG HTTP_CRLF	     \
	"User-Agent: " HTTP_USER_AGENT HTTP_CRLF	     \
	"Connection: " HTTP_CONNECTION HTTP_CRLF
#endif

struct http_client_ctx;

/**
 * @typedef http_receive_cb_t
 * @brief Callback used when TCP data has been received from peer.
 *
 * @param ctx HTTP context.
 * @param pkt Network packet.
 */
typedef void (*http_receive_cb_t)(struct http_client_ctx *ctx,
				  struct net_pkt *pkt);

/**
 * @typedef http_response_cb_t
 * @brief Callback used when a response has been received from peer.
 *
 * @param ctx HTTP context.
 * @param data Received data buffer
 * @param buflen Data buffer len (as specified by user)
 * @param datalen Received data len, if this is larger than buflen,
 * then some data was skipped.
 * @param final_data Does this data buffer contain all the data or
 * is there still more data to come.
 * @param user_data A valid pointer on some user data or NULL
 */
typedef void (*http_response_cb_t)(struct http_client_ctx *ctx,
				   u8_t *data, size_t buflen,
				   size_t datalen,
				   enum http_final_call final_data,
				   void *user_data);

/**
 * HTTP client context information. This contains all the data that is
 * needed when doing HTTP requests.
 */
struct http_client_ctx {
	struct http_parser parser;
	struct http_parser_settings settings;

	/** Server name */
	const char *server;

#if defined(CONFIG_DNS_RESOLVER)
	/** Remember the DNS query id so that it can be cancelled
	 * if the HTTP context is released and the query is active
	 * at that time.
	 */
	u16_t dns_id;
#endif

	struct {
		/** Local socket address */
		struct sockaddr local;

		/** Remote (server) socket address */
		struct sockaddr remote;

		/** IP stack network context */
		struct net_context *ctx;

		/** Network timeout */
		s32_t timeout;

		/** User can define this callback if it wants to have
		 * special handling of the received raw data.
		 */
		http_receive_cb_t receive_cb;
	} tcp;

	/** HTTP request information */
	struct {
		/**
		 * Semaphore to signal HTTP request completion
		 */
		struct k_sem wait;

		/** Hostname to be used in the request */
		const char *host;

		/** User provided data */
		void *user_data;

		/** What method we used here (GET, POST, HEAD etc.)
		 */
		enum http_method method;
	} req;

	/** HTTP response information */
	struct {
		/** User provided HTTP response callback which is called
		 * when a response is received to a sent HTTP request.
		 */
		http_response_cb_t cb;

		/** Where the response is stored, this is to be provided
		 * by the user.
		 */
		u8_t *response_buf;

		/** Where the body starts.
		 */
		u8_t *body_start;

		/** Response buffer maximum length */
		size_t response_buf_len;

		/** Length of the data in the result buf. If the value is
		 * larger than response_buf_len, then it means that the data
		 * is truncated and could not be fully copied into
		 * response_buf. This can only happen if the user did not
		 * set the response callback. If the callback is set, then
		 * the HTTP client API will call response callback many times
		 * so that all the data is delivered to the user.
		 */
		size_t data_len;

		/** HTTP Content-Length field value */
		size_t content_length;

		/** Content length parsed. This should be the same as the
		 * content_length field if parsing was ok.
		 */
		size_t processed;

		/* https://tools.ietf.org/html/rfc7230#section-3.1.2
		 * The status-code element is a 3-digit integer code
		 *
		 * The reason-phrase element exists for the sole purpose of
		 * providing a textual description associated with the
		 * numeric status code. A client SHOULD ignore the
		 * reason-phrase content.
		 */
		char http_status[HTTP_STATUS_STR_SIZE];

		u8_t cl_present:1;
		u8_t body_found:1;
	} rsp;
};

/**
 * HTTP client request. This contains all the data that is needed when doing
 * a HTTP request.
 */
struct http_client_request {
	/** The HTTP method: GET, HEAD, OPTIONS, POST, ... */
	enum http_method method;

	/** The URL for this request, for example: /index.html */
	const char *url;

	/** The HTTP protocol: HTTP/1.1 */
	const char *protocol;

	/** The HTTP header fields (application specific)
	 * The Content-Type may be specified here or in the next field.
	 * Depending on your application, the Content-Type may vary, however
	 * some header fields may remain constant through the application's
	 * life cycle.
	 */
	const char *header_fields;

	/** The value of the Content-Type header field, may be NULL */
	const char *content_type_value;

	/** Hostname to be used in the request */
	const char *host;

	/** Payload, may be NULL */
	const char *payload;

	/** Payload size, may be 0 */
	u16_t payload_size;
};

/**
 * @brief Generic function to send a HTTP request to the network. Normally
 * applications would not need to use this function.
 *
 * @param net_ctx Network context.
 * @param req HTTP request to perform.
 * @param timeout Timeout when doing net_buf allocations.
 *
 * @return Return 0 if ok, and <0 if error.
 */
int http_request(struct net_context *net_ctx, struct http_client_request *req,
		 s32_t timeout);

/**
 * @brief Send a HTTP request to peer.
 *
 * @param http_ctx HTTP context.
 * @param req HTTP request to perform.
 * @param cb Callback to call when the response has been received from peer.
 * @param response_buf Caller supplied buffer where the HTTP response will be
 * stored
 * @param response_buf_len Length of the caller suppied buffer.
 * @param user_data A valid pointer on some user data or NULL
 * @param timeout Amount of time to wait for a reply. If the timeout is 0,
 * then we return immediately and the callback (if set) will be called later.
 *
 * @return Return 0 if ok, and <0 if error.
 */
int http_client_send_req(struct http_client_ctx *http_ctx,
			 struct http_client_request *req,
			 http_response_cb_t cb,
			 u8_t *response_buf,
			 size_t response_buf_len,
			 void *user_data,
			 s32_t timeout);

/**
 * @brief Send a HTTP GET request to peer.
 *
 * @param http_ctx HTTP context.
 * @param url URL to use.
 * @param host Host field in HTTP header. If set to NULL, then server
 * name is used.
 * @param extra_header_fields Any extra header fields that caller wants
 * to add. This can be set to NULL. The format is "name: value\r\n"
 * Example: "Accept: text/plain\r\nConnection: Close\r\n"
 * @param cb Callback to call when the response has been received from peer.
 * @param response_buf Caller supplied buffer where the HTTP request will be
 * stored
 * @param response_buf_len Length of the caller suppied buffer.
 * @param user_data A valid pointer on some user data or NULL
 * @param timeout Amount of time to wait for a reply. If the timeout is 0,
 * then we return immediately and the callback (if set) will be called later.
 *
 * @return Return 0 if ok, and <0 if error.
 */
static inline int http_client_send_get_req(struct http_client_ctx *http_ctx,
					   const char *url,
					   const char *host,
					   const char *extra_header_fields,
					   http_response_cb_t cb,
					   u8_t *response_buf,
					   size_t response_buf_len,
					   void *user_data,
					   s32_t timeout)
{
	struct http_client_request req = {
				.method = HTTP_GET,
				.url = url,
				.host = host,
				.protocol = " " HTTP_PROTOCOL HTTP_CRLF,
				.header_fields = extra_header_fields,
	};

	return http_client_send_req(http_ctx, &req, cb, response_buf,
				    response_buf_len, user_data, timeout);
}

/**
 * @brief Send a HTTP POST request to peer.
 *
 * @param http_ctx HTTP context.
 * @param url URL to use.
 * @param host Host field in HTTP header. If set to NULL, then server
 * name is used.
 * @param extra_header_fields Any extra header fields that caller wants
 * to add. This can be set to NULL. The format is "name: value\r\n"
 * Example: "Accept: text/plain\r\nConnection: Close\r\n"
 * @param content_type Content type of the data.
 * @param payload Payload data.
 * @param cb Callback to call when the response has been received from peer.
 * @param response_buf Caller supplied buffer where the HTTP response will be
 * stored
 * @param response_buf_len Length of the caller suppied buffer.
 * @param user_data A valid pointer on some user data or NULL
 * @param timeout Amount of time to wait for a reply. If the timeout is 0,
 * then we return immediately and the callback (if set) will be called later.
 *
 * @return Return 0 if ok, and <0 if error.
 */
static inline int http_client_send_post_req(struct http_client_ctx *http_ctx,
					    const char *url,
					    const char *host,
					    const char *extra_header_fields,
					    const char *content_type,
					    const char *payload,
					    http_response_cb_t cb,
					    u8_t *response_buf,
					    size_t response_buf_len,
					    void *user_data,
					    s32_t timeout)
{
	struct http_client_request req = {
				.method = HTTP_POST,
				.url = url,
				.host = host,
				.protocol = " " HTTP_PROTOCOL HTTP_CRLF,
				.header_fields = extra_header_fields,
				.content_type_value = content_type,
				.payload = payload,
	};

	return http_client_send_req(http_ctx, &req, cb, response_buf,
				    response_buf_len, user_data, timeout);
}

/**
 * @brief Initialize user supplied HTTP context.
 *
 * @detail Caller can set the various fields in http_ctx after this call
 * if needed.
 *
 * @param http_ctx HTTP context.
 * @param server HTTP server address or host name. If host name is given,
 * then DNS resolver support (CONFIG_DNS_RESOLVER) must be enabled. If caller
 * sets the server parameter as NULL, then it no attempt is done to figure out
 * the remote address and caller must set the address in http_ctx.tcp.remote
 * itself.
 * @param server_port HTTP server TCP port.
 *
 * @return Return 0 if ok, <0 if error.
 */
int http_client_init(struct http_client_ctx *http_ctx,
		     const char *server, u16_t server_port);

/**
 * @brief Release all the resources allocated for HTTP context.
 *
 * @param http_ctx HTTP context.
 */
void http_client_release(struct http_client_ctx *http_ctx);
#endif /* CONFIG_HTTP_CLIENT */

#if defined(CONFIG_HTTP_SERVER)

#include <net/net_context.h>
#include <net/http_parser.h>

struct http_server_ctx;

enum http_url_flags {
	HTTP_URL_STANDARD = 0,
};

/* HTTP header fields struct */
struct http_field_value {
	/** Field name, this variable will point to the beginning of the string
	 *  containing the HTTP field name
	 */
	const char *key;

	/** Value, this variable will point to the beginning of the string
	 *  containing the field value
	 */
	const char *value;

	/** Length of the field name */
	u16_t key_len;

	/** Length of the field value */
	u16_t value_len;
};

typedef int (*http_url_cb_t)(struct http_server_ctx *ctx);

/* HTTP root URL struct, used for pattern matching */
struct http_root_url {
	/** URL */
	const char *root;

	/** Callback that is called when this URL is received */
	http_url_cb_t write_cb;

	/** Length of the URL */
	u16_t root_len;

	/** Flags for this URL (values are from enum http_url_flags) */
	u8_t flags;

	/** Is this URL resource used or not */
	u8_t is_used;
};

/* Collection of URLs that this server will handle */
struct http_server_urls {
	/* First item is the default handler and it is always there.
	 */
	struct http_root_url default_url;
	struct http_root_url urls[CONFIG_HTTP_SERVER_NUM_URLS];
};

#if defined(CONFIG_HTTPS)
/* Internal information for managing HTTPS data */
struct https_context {
	struct net_pkt *rx_pkt;
	struct net_buf *frag;
	struct k_sem tx_sem;
	struct k_fifo rx_fifo;
	int remaining;
};

/**
 * @typedef https_server_cert_cb_t
 * @brief Callback used when the API user needs to setup the
 * HTTPS certs.
 *
 * @param ctx HTTPS server context.
 * @param cert MBEDTLS certificate
 * @param pkey MBEDTLS private key
 *
 * @return 0 if ok, <0 if there is an error
 */
typedef int (*https_server_cert_cb_t)(struct http_server_ctx *ctx,
				      mbedtls_x509_crt *cert,
				      mbedtls_pk_context *pkey);

/**
 * @typedef https_entropy_src_cb_t
 * @brief Callback used when the API user needs to setup the entropy source.
 * @detail This is the same as mbedtls_entropy_f_source_ptr callback.
 *
 * @param data Callback-specific data pointer
 * @param output Data to fill
 * @param len Maximum size to provide
 * @param olen The actual amount of bytes put into the buffer (Can be 0)
 */
typedef int (*https_entropy_src_cb_t)(void *data, unsigned char *output,
				      size_t len, size_t *olen);
#endif /* CONFIG_HTTPS */

typedef int (*http_send_data_t)(struct net_pkt *pkt,
				net_context_send_cb_t cb,
				s32_t timeout,
				void *token,
				void *user_data);

/* The HTTP server context struct */
struct http_server_ctx {
	/** Collection of URLs that this server context will handle */
	struct http_server_urls *urls;

#if defined(CONFIG_NET_IPV4)
	/** IPv4 stack network context for listening */
	struct net_context *net_ipv4_ctx;
#endif
#if defined(CONFIG_NET_IPV6)
	/** IPv6 stack network context for listening */
	struct net_context *net_ipv6_ctx;
#endif

	/** Function that is called when data is received from network. */
	net_context_recv_cb_t recv_cb;

	/** Function that is called when data is sent to network. */
	http_send_data_t send_data;

	/** Network timeout */
	s32_t timeout;

	/** Running status of the server. If true, then the server is enabled.
	 * If false then it is disabled and will not serve clients.
	 * The server is disabled by default after initialization and will need
	 * to be enabled manually.
	 */
	bool enabled;

	/** Is this instance HTTPS or not.
	 */
	bool is_https;

	struct {
		/** From which net_context the request came from */
		struct net_context *net_ctx;

		/** HTTP request timer. After sending a response to the
		 * client, it is possible to wait for any request back via
		 * the same socket. If no response is received, then this
		 * timeout is activated and connection is tore down.
		 */
		struct k_delayed_work timer;

		/** HTTP parser */
		struct http_parser parser;

		/** HTTP parser settings */
		struct http_parser_settings settings;

		/** Collection of header fields */
		struct http_field_value
				field_values[CONFIG_HTTP_HEADER_FIELD_ITEMS];

		/** HTTP Request URL */
		const char *url;

		/** Where the request is stored, this is to be provided
		 * by the user.
		 */
		u8_t *request_buf;

		/** Request buffer maximum length */
		size_t request_buf_len;

		/** Length of the data in the request buf. */
		size_t data_len;

		/** Number of header field elements */
		u16_t field_values_ctr;

		/** URL's length */
		u16_t url_len;

		/** Has the request timer been cancelled. */
		u8_t timer_cancelled;
	} req;

#if defined(CONFIG_HTTPS)
	struct {
		/** HTTPS stack for mbedtls library. */
		u8_t *stack;

		/** HTTPS stack size. */
		int stack_size;

		/** HTTPS thread id */
		k_tid_t tid;

		/** HTTPS thread */
		struct k_thread thread;

		/** Memory pool for RX data */
		struct k_mem_pool *pool;

		/** mbedtls related configuration. */
		struct {
			struct https_context ssl_ctx;
			https_server_cert_cb_t cert_cb;
			https_entropy_src_cb_t entropy_src_cb;
			mbedtls_entropy_context entropy;
			mbedtls_ctr_drbg_context ctr_drbg;
			mbedtls_ssl_context ssl;
			mbedtls_ssl_config conf;
			mbedtls_x509_crt srvcert;
			mbedtls_pk_context pkey;
			u8_t *personalization_data;
			size_t personalization_data_len;
		} mbedtls;
	} https;
#endif /* CONFIG_HTTPS */
};

/**
 * @brief Initialize user supplied HTTP context.
 *
 * @detail Caller can set the various callback fields in http_ctx and
 * http_ctx.req.parser after this call if needed.
 *
 * @param http_ctx HTTP context.
 * @param urls Array of URLs that the server instance will serve. If the
 * server receives a HTTP request into one of the URLs, it will call user
 * supplied callback. If no such URL is registered, a default handler will
 * be called (if set by the user). If no data handler is found, the request
 * is dropped.
 * @param server_addr Socket address of the local network interface and TCP
 * port where the data is being waited. If the socket family is set to
 * AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the
 * address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits
 * zeros for IPv6), then the HTTP server will select proper IP address to bind
 * to. If caller has not specified HTTP listening port, then port 80 is being
 * listened. The parameter can be left NULL in which case a listener to port 80
 * using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then
 * the corresponding disabled service listener is not created.
 * @param request_buf Caller supplied buffer where the HTTP request will be
 * stored
 * @param request_buf_len Length of the caller suppied buffer.
 * @param server_banner Print information about started service. This is only
 * printed if HTTP debugging is activated. The parameter can be set to NULL if
 * no extra prints are needed.
 *
 * @return Return 0 if ok, <0 if error.
 */
int http_server_init(struct http_server_ctx *http_ctx,
		     struct http_server_urls *urls,
		     struct sockaddr *server_addr,
		     u8_t *request_buf,
		     size_t request_buf_len,
		     const char *server_banner);

#if defined(CONFIG_HTTPS)
/**
 * @brief Initialize user supplied HTTP context. This function must be
 * used if HTTPS server is created.
 *
 * @detail Caller can set the various callback fields in http_ctx and
 * http_ctx.req.parser after this call if needed.
 *
 * @param http_ctx HTTP context.
 * @param urls Array of URLs that the server instance will serve. If the
 * server receives a HTTP request into one of the URLs, it will call user
 * supplied callback. If no such URL is registered, a default handler will
 * be called (if set by the user). If no data handler is found, the request
 * is dropped.
 * @param server_addr Socket address of the local network interface and TCP
 * port where the data is being waited. If the socket family is set to
 * AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the
 * address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits
 * zeros for IPv6), then the HTTP server will select proper IP address to bind
 * to. If caller has not specified HTTP listening port, then port 80 is being
 * listened. The parameter can be left NULL in which case a listener to port 80
 * using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then
 * the corresponding disabled service listener is not created.
 * @param request_buf Caller supplied buffer where the HTTP request will be
 * stored
 * @param request_buf_len Length of the caller suppied buffer.
 * @param server_banner Print information about started service. This is only
 * printed if HTTP debugging is activated. The parameter can be set to NULL if
 * no extra prints are needed.
 * @param personalization_data Personalization data (Device specific
 * identifiers) for random number generator. (Can be NULL).
 * @param personalization_data_len Length of the personalization data.
 * @param cert_cb User supplied callback that setups the certifacates.
 * @param entropy_src_cb User supplied callback that setup the entropy. This
 * can be set to NULL, in which case default entropy source is used.
 * @param pool Memory pool for RX data reads.
 * @param https_stack HTTPS thread stack.
 * @param https_stack_len HTTP thread stack size.
 *
 * @return Return 0 if ok, <0 if error.
 */
int https_server_init(struct http_server_ctx *http_ctx,
		      struct http_server_urls *urls,
		      struct sockaddr *server_addr,
		      u8_t *request_buf,
		      size_t request_buf_len,
		      const char *server_banner,
		      u8_t *personalization_data,
		      size_t personalization_data_len,
		      https_server_cert_cb_t cert_cb,
		      https_entropy_src_cb_t entropy_src_cb,
		      struct k_mem_pool *pool,
		      u8_t *https_stack,
		      size_t https_stack_len);
#endif /* CONFIG_HTTPS */

/**
 * @brief Release all the resources allocated for HTTP context.
 *
 * @param http_ctx HTTP context.
 */
void http_server_release(struct http_server_ctx *http_ctx);

/**
 * @brief Enable HTTP server that is related to this context.
 *
 * @detail The HTTP server will start to serve request after this.
 *
 * @param http_ctx HTTP context.
 *
 * @return Previous status of the server.
 */
bool http_server_enable(struct http_server_ctx *http_ctx);

/**
 * @brief Disable HTTP server that is related to this context.
 *
 * @detail The HTTP server will stop to serve request after this.
 *
 * @param http_ctx HTTP context.
 *
 * @return Previous status of the server.
 */
bool http_server_disable(struct http_server_ctx *http_ctx);

/**
 * @brief Helper function that can be used to fill the server (local) sockaddr
 * struct.
 *
 * @param addr Sockaddr struct to be filled.
 * @param myaddr Address that the local IP address. If left NULL, then the
 * proper system address is used.
 * @param port TCP port to use.
 *
 * @return 0 if ok, <0 if error.
 */
int http_server_set_local_addr(struct sockaddr *addr, const char *myaddr,
			       u16_t port);

/**
 * @brief Add a handler for a given URL.
 *
 * @detail Register a handler which is called if the server receives a
 * request to a given URL.
 *
 * @param urls URL struct that will contain all the URLs the user wants to
 * register.
 * @param url URL string.
 * @param flags Flags for the URL.
 * @param write_cb Callback that is called when URL is requested.
 *
 * @return NULL if the URL is already registered, pointer to  URL if
 * registering was ok.
 */
struct http_root_url *http_server_add_url(struct http_server_urls *urls,
					  const char *url, u8_t flags,
					  http_url_cb_t write_cb);

/**
 * @brief Delete the handler for a given URL.
 *
 * @detail Unregister the previously registered URL handler.
 *
 * @param urls URL struct that will contain all the URLs the user has
 * registered.
 * @param url URL string.
 *
 * @return 0 if ok, <0 if error.
 */
int http_server_del_url(struct http_server_urls *urls, const char *url);

/**
 * @brief Add default URL handler.
 *
 * @detail If no URL handler is found, then call this handler. There can
 * be only one default handler in the URL struct.
 *
 * @param urls URL struct that will contain all the URLs the user has
 * registered.
 * @param write_cb Callback that is called when non-registered URL is
 * requested.
 *
 * @return NULL if default URL is already registered, pointer to default
 * URL if registering was ok.
 */
struct http_root_url *http_server_add_default(struct http_server_urls *urls,
					      http_url_cb_t write_cb);

/**
 * @brief Delete the default URL handler.
 *
 * @detail Unregister the previously registered default URL handler.
 *
 * @param urls URL struct that will contain all the URLs the user has
 * registered.
 *
 * @return 0 if ok, <0 if error.
 */
int http_server_del_default(struct http_server_urls *urls);

/**
 * @brief Send HTTP response to client.
 *
 * @detail After sending a response, an optional timeout is started
 * which will wait for any new requests from the peer.
 *
 * @param ctx HTTP context.
 * @param http_header HTTP headers to send.
 * @param html_payload HTML payload to send.
 * @param timeout Timeout to wait until the connection is shutdown.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_wait(struct http_server_ctx *ctx, const char *http_header,
		       const char *html_payload, s32_t timeout);

/**
 * @brief Send HTTP response to client.
 *
 * @detail The connection to peer is torn down right after the response
 * is sent.
 *
 * @param ctx HTTP context.
 * @param http_header HTTP headers to send.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response(struct http_server_ctx *ctx, const char *http_header,
		  const char *html_payload);

/**
 * @brief Send HTTP 400 response to client.
 *
 * @detail HTTP 400 error code indicates a Bad Request
 *
 * @param ctx HTTP context.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_400(struct http_server_ctx *ctx, const char *html_payload);

/**
 * @brief Send HTTP 403 response to client.
 *
 * @detail HTTP 403 error code indicates a Forbidden Request
 *
 * @param ctx HTTP context.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_403(struct http_server_ctx *ctx, const char *html_payload);

/**
 * @brief Send HTTP 404 response to client.
 *
 * @detail HTTP 404 error code indicates a Not Found resource.
 *
 * @param ctx HTTP context.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_404(struct http_server_ctx *ctx, const char *html_payload);

#endif /* CONFIG_HTTP_SERVER */

#endif /* __HTTP_H__ */