-
Notifications
You must be signed in to change notification settings - Fork 0
/
libex_http_app.c
executable file
·387 lines (291 loc) · 13.8 KB
/
libex_http_app.c
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
/* -------------------------------------------------------------------------- */
/* (c) ali@balarabe.com [libex_http_app.c] */
/* -------------------------------------------------------------------------- */
#include "libex_c_precompiled.h"
#include "libex_http_app_.h"
#if defined INCLUDED_LIBEX_HTTP_APP_H
#include <string.h> /* for memset() */
#include "libex_.h"
#include "libex_archive_.h"
#include "libex_array_.h"
#include "libex_bytes_.h"
#include "libex_call_.h"
#include "libex_debug_.h"
#include "libex_error_.h"
#include "libex_html_generator_.h"
#include "libex_http_server_.h"
#include "libex_macro_.h"
#include "libex_pdf_report_.h"
#include "libex_string_class_.h"
#include "libex_stringc_.h"
#include "libex_type_.h"
#include "libex_xml_reader_.h"
#if defined __cplusplus_cli
#pragma unmanaged
#endif
/* TODO: remove this later, once utf8 encoding is used everywhere */
#if defined _MSC_VER
#pragma warning (disable:4133) /* W:L3 incompatible types - from T1 to T2 */
#endif
#define _DOC_NOT_FOUND \
"<!DOCTYPE html PUBLIC '-//w3c//dtd xhtml 1.0 transitional//en'" \
" 'http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd'>" \
"<html xmlns='http://www.w3.org/1999/xhtml'>" \
"<head><title>E404</title></head>" \
"<body bgcolor='#ffffff'>" \
"<div style='position: absolute; left: 55px; width: 350px;" \
" top: 55px; height: 85px; background-color: #FF3300;" \
" font-family: Arial, Helvetica, sans-serif;" \
" font-size: xx-large; font-weight: bolder;" \
" color: #FFFFFF;' align='center'>" \
"404: That page was not found! *</div>" \
"<div style='position: absolute; left: 55px; width: 350px;" \
" top: 150px; font-family: Arial, Helvetica, sans-serif;" \
" font-weight: bolder; color: #FF3300;' align='center'>" \
"* However the server is responding.</div>" \
"</body></html>" /*#*/
/* -------------------------------------------------------------------------- */
NAMESPACE(c_)
typedef enum _m_link_type_enum {
LINK_UNKNOWN = 0, /* _link_type_enum */
LINK_STATIC, /* _link_type_enum */
LINK_PAGE, /* _link_type_enum */
LINK_REPORT, /* _link_type_enum */
LINK_SPECIAL /* _link_type_enum */
}
_link_type_enum; /*enum*/
typedef struct _link_t { /* stores XML in <lx.link url="" type"" path="" */
new_chars_t url; /* _link_t */
_link_type_enum type; /* _link_t */
new_chars_t path; /* _link_t */
}
_link_t;
typedef struct _http_app_t {
HttpServer http; /* _http_app_t */
chars_t site_path; /* _http_app_t */
archive_t archive; /* _http_app_t */
array_t links; /* _http_app_t */
HTTP_APP_DATA_READER_FN(data_reader_fn); /* _http_app_t */
}
_http_app_t;
static bool _is_init = false;
static _http_app_t _t;
/* -------------------------------------------------------------------------- */
/* Functions: Private */
static _link_type_enum _link_type_from_chars( chars_t text_ ) { /*F*/
GO (UID(F465D4));
_link_type_enum ret = LINK_UNKNOWN;
if (equals_icT(text_, _T("static"))) {
ret = LINK_STATIC;
} else if (equals_icT(text_, _T("page"))) {
ret = LINK_PAGE;
} else if (equals_icT(text_, _T("report"))) {
ret = LINK_REPORT;
} else if (equals_icT(text_, _T("special"))) {
ret = LINK_SPECIAL;
} else {
ret = LINK_UNKNOWN;
}
RETURN(ret);
} /* _link_type_from_chars */
/* -------------------------------------------------------------------------- */
static void _fill_links_array( /*F*/
chars_t xml_, /*-*/
array_t links_ ) { /*-*/
GO (UID(FB354B));
Xmlr xml = Xmlr_of_chars(xml_);
bool read = false;
Xmlr_goRoot(xml);
while (!Xmlr_eof(xml)) {
if (Xmlr_isStartTag(xml, _T("lx.links"))) {
read = true;
} else if (read && Xmlr_isEmptyTag(xml, _T("lx.link"))) {
_link_t link = { NULL, LINK_UNKNOWN, NULL };
link.url = T_chars(Xmlr_attr(xml, _T("url")));
{
chars_t const type = Xmlr_attr(xml, _T("type"));
link.type = _link_type_from_chars(type);
}
link.path = T_chars(Xmlr_attr(xml, _T("path")));
Array_addItem(&links_, &link, sizeof(link), NULL);
} else if (read && Xmlr_isEndTag(xml, _T("lx.links"))) {
break;
}
Xmlr_skipTag(xml);
}
freeXmlr(&xml);
RETURN(NIL);
} /* _fill_links_array */
static void _free_links_array( array_t* links_ ) { /*F*/
GO (UID(F87ED7));
size_t i = 0;
const size_t count = Array_count(*links_);
for (i = 0; i < count; i++) {
_link_t* link = CAST(_link_t*, Array_getItemAt(links_, i));
freeT(&link->url);
freeT(&link->path);
}
if (count > 0) {
Array_removeItems(links_);
}
Array_free(links_);
RETURN(NIL);
} /* _free_links_array */
static new_bytes_t _get_page_html( /*F*/
archive_t archive_, /*-*/
str_t settings_, /*-*/
chars_t page_name_ ) { /*-*/
GO (UID(F35B9B));
new_bytes_t ret = { 0, NULL };
new_str_t xml_layout = Archive_getText(archive_, page_name_);
if (!IS_BLANK(xml_layout.cs)) {
const void* NO_CSV = NULL;
new_chars_t html = html_generate(xml_layout.cs, settings_.cs, NO_CSV);
ret = Bytes_fromNewChars(html);
}
freeS(&xml_layout);
RETURN(ret);
} /* _get_page_html */
static new_bytes_t _get_page( /*F*/
archive_t archive_, /*-*/
chars_t page_name_ ) { /*-*/
GO (UID(F41D57));
new_bytes_t ret = { 0, NULL };
new_str_t xml_settings = { NULL };
if (Archive_itemExists(archive_, _T("app.settings.xml"))) {
xml_settings = Archive_getText(archive_, _T("app.settings.xml"));
}
if (Archive_itemExists(archive_, page_name_)) {
ret = _get_page_html(archive_, xml_settings, page_name_);
}
freeS(&xml_settings);
RETURN(ret);
} /* _get_page */
static new_bytes_t _get_report( /*F*/
archive_t archive_, /*-*/
chars_t report_name_ ) { /*-*/
GO (UID(FB2573));
new_bytes_t ret = { 0, NULL };
if (Archive_itemExists(archive_, report_name_)) {
archive_item_t item = Archive_getItem(archive_, report_name_);
new_chars_t xml = Tutf8(CAST(const char*, item.item_data));
new_chars_t sql = T_get_tag(xml, _T("<sql>"), _T("</sql>"));
new_chars_t csv = NULL;
new_Report report = Report_init();
if (_t.data_reader_fn != NULL) {
csv = (*_t.data_reader_fn)(sql);
}
ret = Report_get(report, xml, csv);
freeT(&xml);
freeT(&sql);
freeT(&csv);
Report_free(&report);
}
RETURN(ret);
} /* _get_report */
/* -------------------------------------------------------------------------- */
/* Initializer: */
PUBLIC void HttpApp_init( /*C*/
archive_t archive_, /*-*/
chars_t site_path_ ) { /*-*/
GO (UID(F23B6D));
chars_t LINKS_DOC = _T("app.links.xml");
if (_is_init) {
WARN(_T("HttpApp_init() already called previously."), UID(E863C2));
} else {
_is_init = true;
CLEAR(_t);
_t.archive = archive_;
_t.site_path = site_path_;
_t.links = Array_init(sizeof(_link_t), 100, 0);
_t.data_reader_fn = NULL;
_t.http = HttpServer_init();
HttpServer_setHttpGetHandler(_t.http, &HttpApp_get);
if (Archive_itemExists(archive_, LINKS_DOC)) {
archive_item_t item = Archive_getItem(archive_, LINKS_DOC);
new_chars_t xml = Tutf8(CAST(const char*, item.item_data));
_fill_links_array(xml, _t.links);
freeT(&xml);
}
}
RETURN(NIL);
} /* HttpApp_init */
/* -------------------------------------------------------------------------- */
/* Destructor: */
PUBLIC void HttpApp_free( void ) { /*D*/
GO (UID(F3B8C8));
HttpServer_free(&_t.http);
_free_links_array(&_t.links);
RETURN(NIL);
} /* HttpApp_free */
/* -------------------------------------------------------------------------- */
/* Methods: */
PUBLIC void HttpApp_setDataReader( /*M*/
HTTP_APP_DATA_READER_FN( callback_fn_) ) { /*-*/
GO (UID(F9B8AF));
_t.data_reader_fn = callback_fn_;
RETURN(NIL);
} /* HttpApp_setDataReader */
PUBLIC void HttpApp_run( const int listen_on_port_ ) { /*M*/
GO (UID(F614C0));
HttpServer_run(_t.http, listen_on_port_);
RETURN(NIL);
} /* HttpApp_run */
/* -------------------------------------------------------------------------- */
/* Methods: HTTP */
PUBLIC new_bytes_t HttpApp_get( http_request_t* request_ ) { /*M*/
GO (UID(F5141C));
new_bytes_t ret = { 0, NULL };
size_t i = 0;
const size_t links_count = Array_count(_t.links);
bool is_processed = false;
new_chars_t link = Tutf8(CAST(char*, request_->recv_url));
for (i = 0; i < links_count; i++) {
const _link_t* item =
CAST(const _link_t*, Array_getItemAt(&_t.links, i));
if (equals_icT(link, item->url)) {
if (item->type == LINK_STATIC) {
set_inT(&link, item->path);
break;
} else if (item->type == LINK_PAGE) {
ret = _get_page(_t.archive, item->path);
is_processed = true;
break;
} else if (item->type == LINK_REPORT) {
ret = _get_report(_t.archive, item->path);
is_processed = true;
break;
} else if (item->type == LINK_SPECIAL &&
equals2T(item->path, _T("terminate_server"))) {
HttpServer_stop(_t.http);
is_processed = true;
}
/* TODO: add processing of file links (LINK_FILE??) */
/*
} else if (file_exists(path)) {
ret = file_load_bytes(path);
}
*/
}
}
if (!is_processed) {
new_chars_t path = NULL;
if (ends2T(_t.site_path, _T("/"))) {
path = formatT(_T("%s%s"), _t.site_path, link);
} else {
path = formatT(_T("%s/%s"), _t.site_path, link);
}
if (Archive_itemExists(_t.archive, path)) {
archive_item_t item = Archive_getItem(_t.archive, path);
ret = Bytes_init(item.item_data, item.item_size);
is_processed = true;
} else {
/* TODO: display 404 */
}
freeT(&path);
}
freeT(&link);
RETURN(ret);
} /* HttpApp_get */
END_NAMESPACE /*c_*/
#endif /*eof*/