Skip to content

Commit 0f51f68

Browse files
committed
tidy up C code, refactor html and template
add new functionality to access GET/POST/connection headers, send file and data string TODO: template var struct needs to be freed properly, file() not working, yields "connection dropped" error
1 parent 3bb4ac7 commit 0f51f68

File tree

3 files changed

+272
-83
lines changed

3 files changed

+272
-83
lines changed

stl/httpd.c

Lines changed: 157 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,98 @@
1+
#include <stdio.h>
2+
#include <string.h>
3+
#include <errno.h>
4+
#include <fcntl.h>
5+
#include <sys/stat.h>
6+
17
#include <sys/types.h>
28
#ifndef _WIN32
39
#include <sys/select.h>
410
#include <sys/socket.h>
511
#else
612
#include <winsock2.h>
713
#endif
8-
#include <microhttpd.h>
9-
#include <stdio.h>
1014

15+
#include "microhttpd.h"
1116
#include "httpd.h"
1217
#include "ctemplate.h"
1318
#include "stl.h"
14-
#include <string.h>
15-
#include <errno.h>
1619

20+
// macros
21+
#define WEB_DEBUG(...) if (web_debug_flag) stl_log(__VA_ARGS__)
22+
23+
// forward defines
1724
static struct MHD_Daemon *daemon;
1825
static void (*request_matlab_callback)(void);
19-
TMPL_varlist *web_varlist;
20-
21-
static int
22-
print_out_key (void *cls, enum MHD_ValueKind kind, const char *key,
23-
const char *value)
24-
{
25-
(void)cls; /* Unused. Silent compiler warning. */
26-
(void)kind; /* Unused. Silent compiler warning. */
27-
printf ("%s: %s\n", key, value);
28-
return MHD_YES;
29-
}
26+
static void send_data(void *s, int len, char *type);
27+
static int print_key (void *cls, enum MHD_ValueKind kind, const char *key,
28+
const char *value);
3029

30+
// local copies of the request parameters
31+
static TMPL_varlist *web_varlist;
3132
static struct MHD_Connection *req_connection;
3233
static int req_response_status;
3334
static char *req_url;
3435
static char *req_method;
3536

37+
int web_debug_flag = 1;
38+
3639
static int
3740
page_request (void *cls, struct MHD_Connection *connection,
3841
const char *url, const char *method,
3942
const char *version, const char *upload_data,
4043
size_t *upload_data_size, void **con_cls)
4144
{
42-
(void)cls; /* Unused. Silent compiler warning. */
43-
(void)version; /* Unused. Silent compiler warning. */
44-
(void)upload_data; /* Unused. Silent compiler warning. */
45-
(void)upload_data_size; /* Unused. Silent compiler warning. */
46-
(void)con_cls; /* Unused. Silent compiler warning. */
47-
/*
48-
printf ("New %s request for %s using version %s\n", method, url, version);
49-
50-
51-
MHD_get_connection_values (connection, MHD_HEADER_KIND, print_out_key,
52-
NULL);
5345

46+
/*
47+
MHD_get_connection_values (connection, MHD_HEADER_KIND, print_key, NULL);
48+
MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, print_key, NULL);
49+
*/
5450

55-
printf("URL %s\n", url);
56-
printf("version %s\n", version);
57-
printf("method %s\n", version);
58-
printf("upload data %s\n", upload_data);
59-
*/
60-
req_connection = connection;
61-
req_url = url;
62-
req_method = method;
51+
WEB_DEBUG("web: %s request for URL %s using %s", method, url, version);
52+
53+
// save some of the parameters for access by MATLAB calls
54+
req_connection = connection;
55+
req_url = (char *)url;
56+
req_method = (char *)method;
6357

64-
web_varlist = NULL; // set the template list to empty
58+
// free up the old list somewhere TMPL_free_varlist(varlist)
59+
web_varlist = NULL; // set the template list to empty
6560

66-
// free up the old list somewhere TMPL_free_varlist(varlist)
61+
// set the return status to fail, it will be set by any of the callbacks
62+
req_response_status = MHD_NO;
63+
64+
// call the user's MATLAB code
65+
request_matlab_callback();
6766

68-
/*
69-
MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, print_out_key,
70-
NULL);
71-
*/
72-
req_response_status = MHD_NO;
73-
stl_log("web: %s request for URL %s using %s", method, url, version);
74-
request_matlab_callback();
75-
76-
return req_response_status;
67+
// return the status
68+
return req_response_status;
7769
}
7870

71+
/**
72+
* Send string to the web browser
73+
*/
7974
void
8075
web_html(char *html)
8176
{
82-
struct MHD_Response *response;
8377

84-
//stl_log("web_html: %s", html);
78+
WEB_DEBUG("web_html: %s", html);
8579

86-
response = MHD_create_response_from_buffer(strlen(html), html, MHD_RESPMEM_MUST_COPY);
87-
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/html");
88-
req_response_status = MHD_queue_response(req_connection, MHD_HTTP_OK, response);
89-
MHD_destroy_response(response);
80+
send_data(html, strlen(html), "text/html");
81+
}
82+
83+
/**
84+
* Invoke the template processor
85+
*/
86+
void web_template(char *filename)
87+
{
88+
char buffer[BUFSIZ];
89+
FILE *html = fmemopen(buffer, BUFSIZ, "w");
90+
91+
WEB_DEBUG("web_template: %s", filename);
92+
TMPL_write(filename, 0, 0, web_varlist, html, stderr);
93+
fclose(html);
94+
95+
send_data(buffer, strlen(buffer), "text/html");
9096
}
9197

9298
/**
@@ -95,35 +101,96 @@ web_html(char *html)
95101
void
96102
web_url(char *buf, int buflen)
97103
{
98-
stl_log("web_url: %s", req_url);
104+
WEB_DEBUG("web_url: %s", req_url);
99105
strncpy(buf, req_url, buflen);
100106
}
101107

108+
void
109+
web_file(char *filename, char *type)
110+
{
111+
WEB_DEBUG("web_file: %s, type %s", filename, type);
102112

113+
struct MHD_Response *response;
114+
int fd;
115+
struct stat statbuf;
116+
int ret;
117+
118+
fd = open(filename, O_RDONLY);
119+
if (fd == -1)
120+
stl_error("web_file: couldn't open file %s", filename);
121+
ret = fstat(fd, &statbuf);
122+
if (ret != 0)
123+
stl_error("web_file: couldn't stat file %s", filename);
124+
125+
stl_log("file is %ld bytes", (uint64_t) statbuf.st_size);
126+
response = MHD_create_response_from_fd(statbuf.st_size, fd);
127+
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, type);
128+
MHD_add_response_header(response, MHD_HTTP_HEADER_CONNECTION, "close");
129+
req_response_status = MHD_queue_response(req_connection, MHD_HTTP_OK, response);
130+
MHD_destroy_response(response);
131+
close(fd);
132+
}
103133

104-
/**
105-
* Set a value for the template processor
106-
*/
107-
void web_setvalue(char *name, char *value)
134+
void
135+
web_data(void *data, int len, char *type)
108136
{
109-
stl_log("web_setvalue: %s %s", name, value);
110-
web_varlist = TMPL_add_var(web_varlist, stl_stralloc(name), stl_stralloc(value), NULL);
137+
WEB_DEBUG("web_data: %d bytes, type %s", len, type);
138+
139+
send_data(data, len, type);
111140
}
112141

113-
/**
114-
* Invoke the template processor
115-
*/
116-
void web_template(char *filename)
142+
int
143+
web_ispost()
117144
{
118-
char buffer[BUFSIZ];
119-
FILE *html = fmemopen(buffer, BUFSIZ, "w");
145+
return strcmp(req_method, MHD_HTTP_METHOD_POST);
146+
}
147+
148+
int32_t
149+
web_getarg(char *buf, int len, char *name)
150+
{
151+
char *value = (char *)MHD_lookup_connection_value(req_connection, MHD_GET_ARGUMENT_KIND, name);
120152

121-
bzero(buffer, BUFSIZ);
122-
stl_log("web_template: %s", filename);
123-
TMPL_write(filename, 0, 0, web_varlist, html, stderr);
124-
stl_log("length %d", strlen(buffer));
153+
if (value) {
154+
strncpy(buf, value, len);
155+
buf[len-1] = 0; // for safety with long strings
156+
return 1; // key found
157+
} else
158+
return 0;
159+
}
160+
161+
int32_t
162+
web_postarg(char *buf, int len, char *name)
163+
{
164+
char *value = (char *)MHD_lookup_connection_value(req_connection, MHD_POSTDATA_KIND, name);
165+
166+
if (value) {
167+
strncpy(buf, value, len);
168+
buf[len-1] = 0; // for safety with long strings
169+
return 1; // key found
170+
} else
171+
return 0;
172+
}
173+
174+
int
175+
web_reqheader(char *buf, int len, char *name)
176+
{
177+
char *value = (char *)MHD_lookup_connection_value(req_connection, MHD_HEADER_KIND, name);
178+
179+
if (value) {
180+
strncpy(buf, value, len);
181+
buf[len-1] = 0; // for safety with long strings
182+
return 1; // key found
183+
} else
184+
return 0;
185+
}
125186

126-
web_html(buffer);
187+
/**
188+
* Set a value for the template processor
189+
*/
190+
void web_setvalue(char *name, char *value)
191+
{
192+
WEB_DEBUG("web_setvalue: %s %s", name, value);
193+
web_varlist = TMPL_add_var(web_varlist, stl_stralloc(name), stl_stralloc(value), NULL);
127194
}
128195

129196
void
@@ -142,4 +209,25 @@ web_start(int32_t port, char *callback)
142209
stl_error("web server failed to launch: %s", strerror(errno));
143210

144211
stl_log("web server starting on port %u", port);
212+
}
213+
214+
static void
215+
send_data(void *s, int len, char *type)
216+
{
217+
struct MHD_Response *response;
218+
219+
response = MHD_create_response_from_buffer(len, s, MHD_RESPMEM_MUST_COPY);
220+
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, type);
221+
req_response_status = MHD_queue_response(req_connection, MHD_HTTP_OK, response);
222+
MHD_destroy_response(response);
223+
}
224+
225+
static int
226+
print_key (void *cls, enum MHD_ValueKind kind, const char *key,
227+
const char *value)
228+
{
229+
(void)cls; /* Unused. Silent compiler warning. */
230+
(void)kind; /* Unused. Silent compiler warning. */
231+
printf ("%s: %s\n", key, value);
232+
return MHD_YES;
145233
}

stl/httpd.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
1+
#ifndef __httpd_h_
2+
#define __httpd_h_
13

2-
void web_url(char *buf, int len);
4+
// C functions in httpd.c which are wrapped by webserver.m
35
void web_start(int32_t port, char *callback);
6+
7+
void web_url(char *buf, int len);
8+
int web_ispost();
9+
410
void web_html(char *html);
511
void web_setvalue(char *name, char *value);
6-
void web_template(char *filename);
12+
void web_template(char *filename);
13+
void web_file(char *filename, char *type);
14+
void web_data(void *data, int len, char *type);
15+
16+
int32_t web_getarg(char *buf, int len, char *name);
17+
int32_t web_postarg(char *buf, int len, char *name);
18+
int web_reqheader(char *buf, int len, char *name);
19+
#endif

0 commit comments

Comments
 (0)