Kannel: Open Source WAP and SMS gateway  svn-r5335
test_http_server.c File Reference
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "gwlib/gwlib.h"
#include "gwlib/http.h"

Go to the source code of this file.

Macros

#define MAX_THREADS   1024
 

Functions

static void split_headers (Octstr *headers, List **split)
 
static void client_thread (void *arg)
 
static void help (void)
 
static void sigterm (int signo)
 
int main (int argc, char **argv)
 

Variables

Octstrwhitelist
 
Octstrblacklist
 
Octstrreply_text = NULL
 
int verbose
 
int port
 
int ssl = 0
 
static volatile sig_atomic_t run
 
static Listextra_headers = NULL
 

Macro Definition Documentation

◆ MAX_THREADS

#define MAX_THREADS   1024

Definition at line 71 of file test_http_server.c.

Referenced by main().

Function Documentation

◆ client_thread()

static void client_thread ( void *  arg)
static

Definition at line 104 of file test_http_server.c.

References blacklist, client(), debug(), extra_headers, gwlist_append(), gwlist_create, gwlist_destroy(), gwlist_get(), gwlist_len(), http_accept_request(), http_cgi_variable(), http_close_all_ports(), http_destroy_cgiargs(), HTTP_FOUND, http_header_combine(), http_header_dump(), http_header_value(), HTTP_OK, http_send_reply(), info(), HTTPCGIVar::name, octstr_append_from_hex(), octstr_compare(), octstr_create, octstr_destroy(), octstr_destroy_item(), octstr_dump, octstr_duplicate, octstr_format(), octstr_get_cstr, octstr_imm(), octstr_print(), reply_text, run, ssl, url, HTTPCGIVar::value, verbose, and whitelist.

Referenced by main().

105 {
107  Octstr *body, *url, *ip;
108  List *headers, *resph, *cgivars;
109  HTTPCGIVar *v;
110  Octstr *reply_body, *reply_type;
111  unsigned long n = 0;
112  int status, i;
113 
114  while (run) {
115  client = http_accept_request(port, &ip, &url, &headers, &body, &cgivars);
116 
117  n++;
118  if (client == NULL)
119  break;
120 
121  info(0, "Request for <%s> from <%s>",
123  if (verbose)
124  debug("test.http", 0, "CGI vars were");
125 
126  /*
127  * Don't use gwlist_extract() here, otherwise we don't have a chance
128  * to re-use the cgivars later on.
129  */
130  for (i = 0; i < gwlist_len(cgivars); i++) {
131  if ((v = gwlist_get(cgivars, i)) != NULL && verbose) {
132  octstr_dump(v->name, 0);
133  octstr_dump(v->value, 0);
134  }
135  }
136 
137  if (arg == NULL) {
138  reply_body = octstr_duplicate(reply_text);
139  reply_type = octstr_create("Content-Type: text/plain; "
140  "charset=\"UTF-8\"");
141  } else {
142  reply_body = octstr_duplicate(arg);
143  reply_type = octstr_create("Content-Type: text/vnd.wap.wml");
144  }
145 
146  resph = gwlist_create();
147  gwlist_append(resph, reply_type);
148 
149  status = HTTP_OK;
150 
151  /* check for special URIs and handle those */
152  if (octstr_compare(url, octstr_imm("/quit")) == 0) {
153  run = 0;
154  } else if (octstr_compare(url, octstr_imm("/whitelist")) == 0) {
155  octstr_destroy(reply_body);
156  if (whitelist != NULL) {
157  if (verbose) {
158  debug("test.http.server", 0, "we send a white list");
160  }
161  reply_body = octstr_duplicate(whitelist);
162  } else {
163  reply_body = octstr_imm("");
164  }
165  } else if (octstr_compare(url, octstr_imm("/blacklist")) == 0) {
166  octstr_destroy(reply_body);
167  if (blacklist != NULL) {
168  if (verbose) {
169  debug("test.http.server", 0, "we send a blacklist");
171  }
172  reply_body = octstr_duplicate(blacklist);
173  } else {
174  reply_body = octstr_imm("");
175  }
176  } else if (octstr_compare(url, octstr_imm("/save")) == 0) {
177  /* safe the body into a temporary file */
178  pid_t pid = getpid();
179  FILE *f = fopen(octstr_get_cstr(octstr_format("/tmp/body.%ld.%ld", pid, n)), "w");
180  octstr_print(f, body);
181  fclose(f);
182  } else if (octstr_compare(url, octstr_imm("/redirect/")) == 0) {
183  /* provide us with a HTTP 302 redirection response
184  * will return /redirect/<pid> for the location header
185  * and will return /redirect/ if cgivar loop is set to allow looping
186  */
187  Octstr *redirect_header, *scheme, *uri, *l;
188  pid_t pid = getpid();
189 
190  uri = ((l = http_cgi_variable(cgivars, "loop")) != NULL) ?
191  octstr_format("%s?loop=%s", octstr_get_cstr(url),
192  octstr_get_cstr(l)) :
193  octstr_format("%s%ld", octstr_get_cstr(url), pid);
194 
195  octstr_destroy(reply_body);
196  reply_body = octstr_imm("Here you got a redirection URL that you should follow.");
197  scheme = ssl ? octstr_imm("https://") : octstr_imm("http://");
198  redirect_header = octstr_format("Location: %s%s%s",
199  octstr_get_cstr(scheme),
200  octstr_get_cstr(http_header_value(headers, octstr_imm("Host"))),
201  octstr_get_cstr(uri));
202  gwlist_append(resph, redirect_header);
203  status = HTTP_FOUND; /* will provide 302 */
204  octstr_destroy(uri);
205  } else if (octstr_compare(url, octstr_imm("/mmsc")) == 0) {
206  /* fake a M-Send.conf PDU which is using MMSEncapsulation as body */
207  pid_t pid = getpid();
208  FILE *f;
210  octstr_destroy(reply_body);
211  reply_type = octstr_create("Content-Type: application/vnd.wap.mms-message");
212  reply_body = octstr_create("");
213  octstr_append_from_hex(reply_body,
214  "8c81" /* X-Mms-Message-Type: m-send-conf */
215  "98632d3862343300" /* X-Mms-Transaction-ID: c-8b43 */
216  "8d90" /* X-Mms-MMS-Version: 1.0 */
217  "9280" /* Response-status: Ok */
218  "8b313331373939353434393639383434313731323400"
219  ); /* Message-Id: 13179954496984417124 */
220  resph = gwlist_create();
221  gwlist_append(resph, reply_type);
222  /* safe the M-Send.req body into a temporary file */
223  f = fopen(octstr_get_cstr(octstr_format("/tmp/mms-body.%ld.%ld", pid, n)), "w");
224  octstr_print(f, body);
225  fclose(f);
226  }
227 
228  if (verbose) {
229  debug("test.http", 0, "request headers were");
230  http_header_dump(headers);
231  if (body != NULL) {
232  debug("test.http", 0, "request body was");
233  octstr_dump(body, 0);
234  }
235  }
236 
237  if (extra_headers != NULL)
239 
240  /* return response to client */
241  http_send_reply(client, status, resph, reply_body);
242 
243  octstr_destroy(ip);
245  octstr_destroy(body);
246  octstr_destroy(reply_body);
247  http_destroy_cgiargs(cgivars);
250  }
251 
254  debug("test.http", 0, "Working thread 'client_thread' terminates");
256 }
void info(int err, const char *fmt,...)
Definition: log.c:672
Definition: http.c:2014
Octstr * value
Definition: http.h:216
int verbose
void octstr_append_from_hex(Octstr *ostr, char *hex)
Definition: octstr.c:451
int ssl
void gwlist_append(List *list, void *item)
Definition: list.c:179
Octstr * whitelist
long gwlist_len(List *list)
Definition: list.c:166
static void client(int port)
Definition: test_udp.c:77
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void http_header_combine(List *old_headers, List *new_headers)
Definition: http.c:3068
int octstr_print(FILE *f, Octstr *ostr)
Definition: octstr.c:1191
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
Octstr * http_cgi_variable(List *list, char *name)
Definition: http.c:2836
void http_destroy_cgiargs(List *args)
Definition: http.c:2818
void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body)
Definition: http.c:2695
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Definition: http.h:142
Octstr * name
Definition: http.h:215
static List * extra_headers
HTTPClient * http_accept_request(int port, Octstr **client_ip, Octstr **url, List **headers, Octstr **body, List **cgivars)
Definition: http.c:2571
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
void http_close_all_ports(void)
Definition: http.c:2526
Octstr * http_header_value(List *headers, Octstr *name)
Definition: http.c:2932
Octstr * reply_text
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
#define gwlist_create()
Definition: list.h:136
static volatile sig_atomic_t run
static Octstr * url
Definition: test_xmlrpc.c:84
Definition: list.c:102
Octstr * blacklist
void http_header_dump(List *headers)
Definition: http.c:3427
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145

◆ help()

static void help ( void  )
static

Definition at line 258 of file test_http_server.c.

References info().

Referenced by main().

258  {
259  info(0, "Usage: test_http_server [options...]");
260  info(0, "where options are:");
261  info(0, "-t number");
262  info(0, " set number of working threads to use (default: 1)");
263  info(0, "-v number");
264  info(0, " set log level for stderr logging (default: 0 - debug)");
265  info(0, "-l logfile");
266  info(0, " log all output to a file");
267  info(0, "-f file");
268  info(0, " use a specific file content for the response body");
269  info(0, "-r reply_text");
270  info(0, " defines which static text to use for replies");
271  info(0, "-h");
272  info(0, " provides this usage help information");
273  info(0, "-q");
274  info(0, " don't be too verbose with output");
275  info(0, "-p port");
276  info(0, " bind server to a specific port");
277  info(0, "-s");
278  info(0, " be an SSL-enabled server");
279  info(0, "-c ssl_cert");
280  info(0, " file of the SSL certificate to use");
281  info(0, "-k ssl_key");
282  info(0, " file of the SSL private key to use");
283  info(0, "-w white_list");
284  info(0, " file that is used for whitelist");
285  info(0, "-b black_list");
286  info(0, " file that is used for blacklist");
287  info(0, "-H filename");
288  info(0, " read HTTP headers from file 'filename' and add them to");
289  info(0, " the request for url 'url'");
290  info(0, "specific URIs with special functions are:");
291  info(0, " /quite - shutdown the HTTP server");
292  info(0, " /whitelist - provides the -w whitelist as response");
293  info(0, " /blacklist - provides the -b blacklist as response");
294  info(0, " /save - save a HTTP POST request body to a file /tmp/body.<pid>.<n>");
295  info(0, " where <pid> is the process id and <n> is the received request number");
296  info(0, " /redirect/ - respond with HTTP 302 and the location /redirect/<pid>");
297  info(0, " where <pid> is the process id. if a cgivar loop=<something> is given");
298  info(0, " then HTTP responses will end up in a loop.");
299  info(0, " /mmsc - fake a MMSC HTTP interface for M-Send.req PDUs send by a");
300  info(0, " mobile MMS-capable device, responds with a M-Send.conf PDU and");
301  info(0, " saves the M-Send.req body to a file /tmp/mms-body.<pid>.<n> in");
302  info(0, " MMSEncapsulation encoded binary format");
303 
304 }
void info(int err, const char *fmt,...)
Definition: log.c:672

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 311 of file test_http_server.c.

References blacklist, client_thread(), debug(), error(), extra_headers, filename, getopt(), GW_DEBUG, GW_NON_EXCL, gwlib_init(), gwlib_shutdown(), gwlist_destroy(), gwthread_create, gwthread_join(), help(), http_open_port(), log_open(), log_set_output_level(), MAX_THREADS, octstr_create, octstr_destroy(), octstr_destroy_item(), octstr_dump, octstr_get_cstr, octstr_read_file(), optarg, panic, reply_text, run, sigterm(), split_headers(), ssl, threads, verbose, and whitelist.

311  {
312  int i, opt, use_threads;
313  struct sigaction act;
314  char *filename;
315  Octstr *log_filename;
316  Octstr *file_contents;
317 #ifdef HAVE_LIBSSL
318  Octstr *ssl_server_cert_file = NULL;
319  Octstr *ssl_server_key_file = NULL;
320 #endif
321  char *whitelist_name;
322  char *blacklist_name;
323  int white_asked,
324  black_asked;
325  long threads[MAX_THREADS];
326  FILE *fp;
327 
328  gwlib_init();
329 
330  act.sa_handler = sigterm;
331  sigemptyset(&act.sa_mask);
332  act.sa_flags = 0;
333  sigaction(SIGTERM, &act, NULL);
334  sigaction(SIGINT, &act, NULL);
335 
336  port = 8080;
337  use_threads = 1;
338  verbose = 1;
339  run = 1;
340  filename = NULL;
341  log_filename = NULL;
342  blacklist_name = NULL;
343  whitelist_name = NULL;
344  white_asked = 0;
345  black_asked = 0;
346 
347  reply_text = octstr_create("Sent.");
348 
349  while ((opt = getopt(argc, argv, "hqv:p:t:f:l:sc:k:b:w:r:H:")) != EOF) {
350  switch (opt) {
351  case 'v':
353  break;
354 
355  case 'q':
356  verbose = 0;
357  break;
358 
359  case 'h':
360  help();
361  exit(0);
362 
363  case 'p':
364  port = atoi(optarg);
365  break;
366 
367  case 't':
368  use_threads = atoi(optarg);
369  if (use_threads > MAX_THREADS)
370  use_threads = MAX_THREADS;
371  break;
372 
373  case 'c':
374 #ifdef HAVE_LIBSSL
375  octstr_destroy(ssl_server_cert_file);
376  ssl_server_cert_file = octstr_create(optarg);
377 #endif
378  break;
379 
380  case 'k':
381 #ifdef HAVE_LIBSSL
382  octstr_destroy(ssl_server_key_file);
383  ssl_server_key_file = octstr_create(optarg);
384 #endif
385  break;
386 
387  case 's':
388 #ifdef HAVE_LIBSSL
389  ssl = 1;
390 #endif
391  break;
392 
393  case 'f':
394  filename = optarg;
395  break;
396 
397  case 'l':
398  octstr_destroy(log_filename);
399  log_filename = octstr_create(optarg);
400  break;
401 
402  case 'w':
403  whitelist_name = optarg;
404  if (whitelist_name == NULL)
405  whitelist_name = "";
406  white_asked = 1;
407  break;
408 
409  case 'b':
410  blacklist_name = optarg;
411  if (blacklist_name == NULL)
412  blacklist_name = "";
413  black_asked = 1;
414  break;
415 
416  case 'r':
419  break;
420 
421  case 'H': {
422  Octstr *cont;
423 
424  fp = fopen(optarg, "a");
425  if (fp == NULL)
426  panic(0, "Cannot open header text file %s", optarg);
427  cont = octstr_read_file(optarg);
428  if (cont == NULL)
429  panic(0, "Cannot read header text");
430  debug("", 0, "headers are");
431  octstr_dump(cont, 0);
433  fclose(fp);
434  octstr_destroy(cont);
435  break;
436  }
437 
438  case '?':
439  default:
440  error(0, "Invalid option %c", opt);
441  help();
442  panic(0, "Stopping.");
443  }
444  }
445 
446  if (log_filename != NULL) {
447  log_open(octstr_get_cstr(log_filename), GW_DEBUG, GW_NON_EXCL);
448  octstr_destroy(log_filename);
449  }
450 
451  if (filename == NULL)
452  file_contents = NULL;
453  else
454  file_contents = octstr_read_file(filename);
455 
456  if (white_asked) {
457  whitelist = octstr_read_file(whitelist_name);
458  if (whitelist == NULL)
459  panic(0, "Cannot read the whitelist");
460  }
461 
462  if (black_asked) {
463  blacklist = octstr_read_file(blacklist_name);
464  if (blacklist == NULL)
465  panic(0, "Cannot read the blacklist");
466  }
467 
468 #ifdef HAVE_LIBSSL
469  /*
470  * check if we are doing a SSL-enabled server version here
471  * load the required cert and key file
472  */
473  if (ssl) {
474  if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) {
475  conn_use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file);
476  octstr_destroy(ssl_server_cert_file);
477  octstr_destroy(ssl_server_key_file);
478  } else {
479  panic(0, "certificate and public key need to be given!");
480  }
481  }
482 #endif
483 
484  if (http_open_port(port, ssl) == -1)
485  panic(0, "http_open_server failed");
486 
487  /*
488  * Do the real work in a separate thread so that the main
489  * thread can catch signals safely.
490  */
491  for (i = 0; i < use_threads; ++i)
492  threads[i] = gwthread_create(client_thread, file_contents);
493 
494  /* wait for all working threads */
495  for (i = 0; i < use_threads; ++i)
497 
500 
501  debug("test.http", 0, "Program exiting normally.");
502  gwlib_shutdown();
503  return 0;
504 }
void error(int err, const char *fmt,...)
Definition: log.c:648
#define MAX_THREADS
Definition: http.c:2014
int verbose
int threads
Definition: fakewap.c:239
static void help(void)
int ssl
Octstr * whitelist
static void client_thread(void *arg)
void gwthread_join(long thread)
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
void log_set_output_level(enum output_level level)
Definition: log.c:253
static List * extra_headers
Definition: log.h:69
static void sigterm(int signo)
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
char filename[FILENAME_MAX+1]
Definition: log.c:171
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
int http_open_port(int port, int ssl)
Definition: http.c:2509
Octstr * octstr_read_file(const char *filename)
Definition: octstr.c:1548
int log_open(char *filename, int level, enum excl_state excl)
Definition: log.c:375
Octstr * reply_text
static void split_headers(Octstr *headers, List **split)
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
char * optarg
Definition: attgetopt.c:82
#define panic
Definition: log.h:87
void gwlib_shutdown(void)
Definition: gwlib.c:94
static volatile sig_atomic_t run
void gwlib_init(void)
Definition: gwlib.c:78
Octstr * blacklist
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145

◆ sigterm()

static void sigterm ( int  signo)
static

Definition at line 306 of file test_http_server.c.

References debug(), and run.

Referenced by main().

306  {
307  run = 0;
308  debug("test.gwlib", 0, "Signal %d received, quitting.", signo);
309 }
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static volatile sig_atomic_t run

◆ split_headers()

static void split_headers ( Octstr headers,
List **  split 
)
static

Definition at line 81 of file test_http_server.c.

References gwlist_append(), gwlist_create, octstr_copy, octstr_get_char(), octstr_len(), split, and start.

Referenced by main().

82 {
83  long start;
84  long pos;
85 
86  *split = gwlist_create();
87  start = 0;
88  for (pos = 0; pos < octstr_len(headers); pos++) {
89  if (octstr_get_char(headers, pos) == '\n') {
90  Octstr *line;
91 
92  if (pos == start) {
93  /* Skip empty lines */
94  start = pos + 1;
95  continue;
96  }
97  line = octstr_copy(headers, start, pos - start);
98  start = pos + 1;
99  gwlist_append(*split, line);
100  }
101  }
102 }
void gwlist_append(List *list, void *item)
Definition: list.c:179
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
Definition: octstr.c:118
static List * split
Definition: test_http.c:88
#define gwlist_create()
Definition: list.h:136
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
static int start

Variable Documentation

◆ blacklist

Octstr * blacklist

Definition at line 73 of file test_http_server.c.

Referenced by client_thread(), and main().

◆ extra_headers

List* extra_headers = NULL
static

Definition at line 79 of file test_http_server.c.

Referenced by client_thread(), and main().

◆ port

int port

Definition at line 76 of file test_http_server.c.

◆ reply_text

Octstr* reply_text = NULL

Definition at line 74 of file test_http_server.c.

Referenced by client_thread(), and main().

◆ run

volatile sig_atomic_t run
static

Definition at line 78 of file test_http_server.c.

Referenced by client_thread(), main(), and sigterm().

◆ ssl

◆ verbose

int verbose

Definition at line 76 of file test_http_server.c.

Referenced by client_thread(), and main().

◆ whitelist

Octstr* whitelist

Definition at line 73 of file test_http_server.c.

Referenced by client_thread(), and main().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.