Imported Upstream version 0.9.0
[deb_shairplay.git] / src / lib / http_response.c
1 /**
2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <assert.h>
19
20 #include "http_response.h"
21 #include "compat.h"
22
23 struct http_response_s {
24 int complete;
25 int disconnect;
26
27 char *data;
28 int data_size;
29 int data_length;
30 };
31
32
33 static void
34 http_response_add_data(http_response_t *response, const char *data, int datalen)
35 {
36 int newdatasize;
37
38 assert(response);
39 assert(data);
40 assert(datalen > 0);
41
42 newdatasize = response->data_size;
43 while (response->data_size+datalen > newdatasize) {
44 newdatasize *= 2;
45 }
46 if (newdatasize != response->data_size) {
47 response->data = realloc(response->data, newdatasize);
48 assert(response->data);
49 }
50 memcpy(response->data+response->data_length, data, datalen);
51 response->data_length += datalen;
52 }
53
54 http_response_t *
55 http_response_init(const char *protocol, int code, const char *message)
56 {
57 http_response_t *response;
58 char codestr[4];
59
60 assert(code >= 100 && code < 1000);
61
62 /* Convert code into string */
63 memset(codestr, 0, sizeof(codestr));
64 snprintf(codestr, sizeof(codestr), "%u", code);
65
66 response = calloc(1, sizeof(http_response_t));
67 if (!response) {
68 return NULL;
69 }
70
71 /* Allocate response data */
72 response->data_size = 1024;
73 response->data = malloc(response->data_size);
74 if (!response->data) {
75 free(response);
76 return NULL;
77 }
78
79 /* Add first line of response to the data array */
80 http_response_add_data(response, protocol, strlen(protocol));
81 http_response_add_data(response, " ", 1);
82 http_response_add_data(response, codestr, strlen(codestr));
83 http_response_add_data(response, " ", 1);
84 http_response_add_data(response, message, strlen(message));
85 http_response_add_data(response, "\r\n", 2);
86
87 return response;
88 }
89
90 void
91 http_response_destroy(http_response_t *response)
92 {
93 if (response) {
94 free(response->data);
95 free(response);
96 }
97 }
98
99 void
100 http_response_add_header(http_response_t *response, const char *name, const char *value)
101 {
102 assert(response);
103 assert(name);
104 assert(value);
105
106 http_response_add_data(response, name, strlen(name));
107 http_response_add_data(response, ": ", 2);
108 http_response_add_data(response, value, strlen(value));
109 http_response_add_data(response, "\r\n", 2);
110 }
111
112 void
113 http_response_finish(http_response_t *response, const char *data, int datalen)
114 {
115 assert(response);
116 assert(datalen==0 || (data && datalen > 0));
117
118 if (data && datalen > 0) {
119 const char *hdrname = "Content-Length";
120 char hdrvalue[16];
121
122 memset(hdrvalue, 0, sizeof(hdrvalue));
123 snprintf(hdrvalue, sizeof(hdrvalue)-1, "%d", datalen);
124
125 /* Add Content-Length header first */
126 http_response_add_data(response, hdrname, strlen(hdrname));
127 http_response_add_data(response, ": ", 2);
128 http_response_add_data(response, hdrvalue, strlen(hdrvalue));
129 http_response_add_data(response, "\r\n\r\n", 4);
130
131 /* Add data to the end of response */
132 http_response_add_data(response, data, datalen);
133 } else {
134 /* Add extra end of line after headers */
135 http_response_add_data(response, "\r\n", 2);
136 }
137 response->complete = 1;
138 }
139
140 void
141 http_response_set_disconnect(http_response_t *response, int disconnect)
142 {
143 assert(response);
144
145 response->disconnect = !!disconnect;
146 }
147
148 int
149 http_response_get_disconnect(http_response_t *response)
150 {
151 assert(response);
152
153 return response->disconnect;
154 }
155
156 const char *
157 http_response_get_data(http_response_t *response, int *datalen)
158 {
159 assert(response);
160 assert(datalen);
161 assert(response->complete);
162
163 *datalen = response->data_length;
164 return response->data;
165 }