proxy_server.c
Go to the documentation of this file.
1 // Copyright (c) 2014 Cesanta Software Limited
2 // All rights reserved
3 //
4 // To build and run this example:
5 // git clone https://github.com/cesanta/net_skeleton.git
6 // git clone https://github.com/cesanta/mongoose.git
7 // cd mongoose/examples
8 // make proxy
9 // ./proxy
10 //
11 // Configure your browser to use localhost:2014 as a proxy for all protocols
12 // Then, navigate to https://cesanta.com
13 
14 #include <sys/stat.h>
15 #include <signal.h>
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 
22 #ifdef _WIN32
23 #define sleep(x) Sleep((x) * 1000)
24 #else
25 #include <unistd.h>
26 #endif
27 
28 #include "mongoose.h"
29 
30 static int s_received_signal = 0;
31 static struct mg_server *s_server = NULL;
32 
33 #define SSE_CONNECTION ((void *) 1)
34 
35 static void elog(int do_exit, const char *fmt, ...) {
36  va_list ap;
37  va_start(ap, fmt);
38  vfprintf(stderr, fmt, ap);
39  va_end(ap);
40  fputc('\n', stderr);
41  if (do_exit) exit(EXIT_FAILURE);
42 }
43 
44 static void signal_handler(int sig_num) {
45  signal(sig_num, signal_handler);
46  s_received_signal = sig_num;
47 }
48 
49 static int sse_push(struct mg_connection *conn, enum mg_event ev) {
50  if (ev == MG_POLL && conn->connection_param == SSE_CONNECTION) {
51  mg_printf(conn, "data: %s\r\n\r\n", (const char *) conn->callback_param);
52  }
53  return MG_TRUE;
54 }
55 
56 static void *sse_pusher_thread_func(void *param) {
57  while (s_received_signal == 0) {
58  mg_wakeup_server_ex(s_server, sse_push, "%lu %s",
59  (unsigned long) time(NULL), (const char *) param);
60  sleep(1);
61  }
62  return NULL;
63 }
64 
65 // Return: 1 if regular file, 2 if directory, 0 if not found
66 static int exists(const char *path) {
67  struct stat st;
68  return stat(path, &st) != 0 ? 0 : S_ISDIR(st.st_mode) == 0 ? 1 : 2;
69 }
70 
71 // Return: 1 if regular file, 2 if directory, 0 if not found
72 static int is_local_file(const char *uri, char *path, size_t path_len) {
73  snprintf(path, path_len, "%s/%s",
74  mg_get_option(s_server, "document_root"), uri);
75  return exists(path);
76 }
77 
78 static int try_to_serve_locally(struct mg_connection *conn) {
79  char path[500], buf[2000];
80  int n, res;
81  FILE *fp = NULL;
82 
83  if ((res = is_local_file(conn->uri, path, sizeof(path))) == 2) {
84  strncat(path, "/index.html", sizeof(path) - strlen(path) - 1);
85  res = exists(path);
86  printf("PATH: [%s]\n", path);
87  }
88  if (res == 0) return MG_FALSE;
89 
90  if ((fp = fopen(path, "rb")) != NULL) {
91  printf("Serving [%s] locally \n", path);
92  mg_send_header(conn, "Connection", "close");
93  mg_send_header(conn, "Content-Type", mg_get_mime_type(path, "text/plain"));
94  while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
95  mg_send_data(conn, buf, n);
96  }
97  mg_send_data(conn, "", 0);
98  fclose(fp);
99  }
100  return fp == NULL ? MG_FALSE : MG_TRUE;
101 }
102 
103 static int is_resource_present_locally(const char *uri) {
104  char path[500];
105  return is_local_file(uri, path, sizeof(path)) || strcmp(uri, "/api/sse") == 0;
106 }
107 
108 static int proxy_event_handler(struct mg_connection *conn, enum mg_event ev) {
109  static const char target_url[] = "http://cesanta.com";
110  static int target_url_size = sizeof(target_url) - 1;
111  const char *host;
112 
113  switch (ev) {
114  case MG_REQUEST:
115  host = mg_get_header(conn, "Host");
116  printf("[%s] [%s] [%s]\n", conn->request_method, conn->uri,
117  host == NULL ? "" : host);
118  if (strstr(conn->uri, "/qqq") != NULL) s_received_signal = SIGTERM;
119 
120  // Proxied HTTPS requests use "CONNECT foo.com:443"
121  // Proxied HTTP requests use "GET http://..... "
122  // Serve requests for target_url from the local FS.
123  if (memcmp(conn->uri, target_url, target_url_size) == 0 &&
124  is_resource_present_locally(conn->uri + target_url_size)) {
125  conn->uri += target_url_size; // Leave only path in the URI
126  }
127 
128  if (strcmp(conn->uri, "/api/sse") == 0) {
130  mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n"
131  "Content-Type: text/event-stream\r\n"
132  "Cache-Control: no-cache\r\n\r\n");
133  return MG_MORE;
134  }
135 
136  if (host != NULL && strstr(host, "cesanta") != NULL) {
137  return try_to_serve_locally(conn);
138  }
139 
140  // Enable man-in-the-middle SSL mode for oracle.com
141  if (!strcmp(conn->request_method, "CONNECT") &&
142  !strcmp(host, "oracle.com")) {
143  mg_terminate_ssl(conn, "ssl_cert.pem"); // MUST return MG_MORE after
144  return MG_MORE;
145  }
146 
147  return MG_FALSE;
148  case MG_AUTH:
149  return MG_TRUE;
150  default:
151  return MG_FALSE;
152  }
153 }
154 
155 static void setopt(struct mg_server *s, const char *opt, const char *val) {
156  const char *err_msg = mg_set_option(s, opt, val);
157  if (err_msg != NULL) {
158  elog(1, "Error setting [%s]: [%s]", opt, err_msg);
159  }
160 }
161 
162 int main(int argc, char *argv[]) {
163  const char *port = "2014", *dump = NULL, *root = "proxy_web_root";
164  int i;
165 
166  // Parse command line options
167  for (i = 1; i < argc; i++) {
168  if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
169  port = argv[++i];
170  } else if (strcmp(argv[i], "-root") == 0 && i + 1 < argc) {
171  root = argv[++i];
172  } else if (strcmp(argv[i], "-dump") == 0 && i + 1 < argc) {
173  dump = argv[++i];
174  } else {
175  elog(1, "Usage: %s [-cert FILE] [-ca_cert FILE] [-port PORT]", argv[0]);
176  }
177  }
178 
179  signal(SIGTERM, signal_handler);
180  signal(SIGINT, signal_handler);
181 
182  // Create and configure proxy server
183  s_server = mg_create_server(NULL, &proxy_event_handler);
184  setopt(s_server, "enable_proxy", "yes");
185  setopt(s_server, "document_root", root);
186  setopt(s_server, "listening_port", port);
187  setopt(s_server, "hexdump_file", dump);
188 
189  // Start two SSE pushing threads
190  mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_1");
191  mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_2");
192 
193  // Start serving in the main thread
194  printf("Starting on port %s\n", mg_get_option(s_server, "listening_port"));
195  while (s_received_signal == 0) {
196  mg_poll_server(s_server, 1000);
197  }
198  printf("Existing on signal %d\n", s_received_signal);
199  mg_destroy_server(&s_server);
200 
201  return EXIT_SUCCESS;
202 }
static struct mg_server * s_server
Definition: proxy_server.c:31
void mg_send_header(struct mg_connection *c, const char *name, const char *v)
Definition: mongoose.c:2759
static int sse_push(struct mg_connection *conn, enum mg_event ev)
Definition: proxy_server.c:49
static int exists(const char *path)
Definition: proxy_server.c:66
int mg_terminate_ssl(struct mg_connection *c, const char *cert)
#define SSE_CONNECTION
Definition: proxy_server.c:33
void * mg_start_thread(void *(*func)(void *), void *param)
void * connection_param
Definition: mongoose.h:56
int stat(const char *path, struct stat *buffer)
static void signal_handler(int sig_num)
Definition: proxy_server.c:44
const char * mg_get_header(const struct mg_connection *ri, const char *s)
Definition: mongoose.c:2566
const char * uri
Definition: mongoose.h:34
static void * sse_pusher_thread_func(void *param)
Definition: proxy_server.c:56
static int is_resource_present_locally(const char *uri)
Definition: proxy_server.c:103
const char * mg_get_mime_type(const char *path, const char *default_mime_type)
Definition: mongoose.c:3158
struct mg_server * mg_create_server(void *server_data, mg_handler_t handler)
Definition: mongoose.c:5431
const char * mg_get_option(const struct mg_server *server, const char *name)
Definition: mongoose.c:5425
static int res
unsigned int i
Definition: unit1303.c:79
time_t mg_poll_server(struct mg_server *server, int milliseconds)
Definition: mongoose.c:4965
static int s_received_signal
Definition: proxy_server.c:30
static void setopt(struct mg_server *s, const char *opt, const char *val)
Definition: proxy_server.c:155
static int proxy_event_handler(struct mg_connection *conn, enum mg_event ev)
Definition: proxy_server.c:108
static void elog(int do_exit, const char *fmt,...)
Definition: proxy_server.c:35
static int try_to_serve_locally(struct mg_connection *conn)
Definition: proxy_server.c:78
static int is_local_file(const char *uri, char *path, size_t path_len)
Definition: proxy_server.c:72
#define printf
Definition: curl_printf.h:40
int main(int argc, char *argv[])
Definition: proxy_server.c:162
mg_event
Definition: mongoose.h:62
#define vfprintf
Definition: curl_printf.h:44
static unsigned short port
Definition: sockfilt.c:137
struct Curl_tree * root
Definition: unit1309.c:73
size_t fread(void *, size_t, size_t, FILE *)
char buf[3]
Definition: unit1398.c:32
const char * mg_set_option(struct mg_server *server, const char *name, const char *value)
Definition: mongoose.c:5143
size_t mg_printf(struct mg_connection *conn, const char *fmt,...)
Definition: mongoose.c:1949
#define snprintf
Definition: curl_printf.h:42
void * callback_param
Definition: mongoose.h:57
const char * request_method
Definition: mongoose.h:33
static void dump(const char *text, FILE *stream, unsigned char *ptr, size_t size, char nohex)
Definition: debug.c:34
void mg_destroy_server(struct mg_server **server)
Definition: mongoose.c:4969
void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb, const char *fmt,...)
Definition: mongoose.c:5405
const char * path
Definition: util.c:192
size_t mg_send_data(struct mg_connection *c, const void *data, int data_len)
Definition: mongoose.c:2778


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16