Move src to src/lib, include to src/include, test to src/test.
[deb_shairplay.git] / src / lib / http_response.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <assert.h>
5
6 #include "http_response.h"
7
8 struct http_response_s {
9 int complete;
10
11 char *data;
12 int data_size;
13 int data_length;
14 };
15
16
17 static void
18 http_response_add_data(http_response_t *response, const char *data, int datalen)
19 {
20 int newdatasize;
21
22 assert(response);
23 assert(data);
24 assert(datalen > 0);
25
26 newdatasize = response->data_size;
27 while (response->data_size+datalen > newdatasize) {
28 newdatasize *= 2;
29 }
30 if (newdatasize != response->data_size) {
31 response->data = realloc(response->data, newdatasize);
32 assert(response->data);
33 }
34 memcpy(response->data+response->data_length, data, datalen);
35 response->data_length += datalen;
36 }
37
38 http_response_t *
39 http_response_init(const char *protocol, int code, const char *message)
40 {
41 http_response_t *response;
42 char codestr[4];
43
44 assert(code >= 100 && code < 1000);
45
46 /* Convert code into string */
47 memset(codestr, 0, sizeof(codestr));
48 snprintf(codestr, sizeof(codestr), "%u", code);
49
50 response = calloc(1, sizeof(http_response_t));
51 if (!response) {
52 return NULL;
53 }
54
55 /* Allocate response data */
56 response->data_size = 1024;
57 response->data = malloc(response->data_size);
58 if (!response->data) {
59 free(response);
60 return NULL;
61 }
62
63 /* Add first line of response to the data array */
64 http_response_add_data(response, protocol, strlen(protocol));
65 http_response_add_data(response, " ", 1);
66 http_response_add_data(response, codestr, strlen(codestr));
67 http_response_add_data(response, " ", 1);
68 http_response_add_data(response, message, strlen(message));
69 http_response_add_data(response, "\r\n", 2);
70
71 return response;
72 }
73
74 void
75 http_response_destroy(http_response_t *response)
76 {
77 if (response) {
78 free(response->data);
79 free(response);
80 }
81 }
82
83 void
84 http_response_add_header(http_response_t *response, const char *name, const char *value)
85 {
86 assert(response);
87 assert(name);
88 assert(value);
89
90 http_response_add_data(response, name, strlen(name));
91 http_response_add_data(response, ": ", 2);
92 http_response_add_data(response, value, strlen(value));
93 http_response_add_data(response, "\r\n", 2);
94 }
95
96 void
97 http_response_finish(http_response_t *response, const char *data, int datalen)
98 {
99 assert(response);
100 assert(datalen==0 || (data && datalen > 0));
101
102 if (data && datalen > 0) {
103 const char *hdrname = "Content-Length";
104 char hdrvalue[16];
105
106 memset(hdrvalue, 0, sizeof(hdrvalue));
107 snprintf(hdrvalue, sizeof(hdrvalue)-1, "%d", datalen);
108
109 /* Add Content-Length header first */
110 http_response_add_data(response, hdrname, strlen(hdrname));
111 http_response_add_data(response, ": ", 2);
112 http_response_add_data(response, hdrvalue, strlen(hdrvalue));
113 http_response_add_data(response, "\r\n\r\n", 4);
114
115 /* Add data to the end of response */
116 http_response_add_data(response, data, datalen);
117 } else {
118 /* Add extra end of line after headers */
119 http_response_add_data(response, "\r\n", 2);
120 }
121 response->complete = 1;
122 }
123
124 const char *
125 http_response_get_data(http_response_t *response, int *datalen)
126 {
127 assert(response);
128 assert(datalen);
129 assert(response->complete);
130
131 *datalen = response->data_length;
132 return response->data;
133 }