Newer
Older
file_name, file_name_len);
}
}
// Scan body, search for terminating boundary
for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
if (buf[pos] == '-' && !memcmp(buf, &buf[pos], bl - 2)) {
if (data_len != NULL) *data_len = (pos - 2) - hl;
if (data != NULL) *data = buf + hl;
return pos;
}
}
return 0;
}
const char **mg_get_valid_option_names(void) {
return static_config_options;
static int get_option_index(const char *name) {
for (i = 0; static_config_options[i * 2] != NULL; i++) {
if (strcmp(static_config_options[i * 2], name) == 0) {
return i;
}
return -1;
}
static void set_default_option_values(char **opts) {
const char *value, **all_opts = mg_get_valid_option_names();
int i;
for (i = 0; all_opts[i * 2] != NULL; i++) {
value = all_opts[i * 2 + 1];
if (opts[i] == NULL && value != NULL) {
opts[i] = mg_strdup(value);
// Valid listening port spec is: [ip_address:]port, e.g. "80", "127.0.0.1:3128"
static int parse_port_string(const char *str, union socket_address *sa) {
unsigned int a, b, c, d, port;
int len = 0;
#ifdef MONGOOSE_USE_IPV6
// MacOS needs that. If we do not zero it, subsequent bind() will fail.
// Also, all-zeroes in the socket address means binding to all addresses
// for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
memset(sa, 0, sizeof(*sa));
sa->sin.sin_family = AF_INET;
if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
// Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
sa->sin.sin_port = htons((uint16_t) port);
#if defined(MONGOOSE_USE_IPV6)
} else if (sscanf(str, "[%49[^]]]:%u%n", buf, &port, &len) == 2 &&
inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
// IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
sa->sin6.sin6_family = AF_INET6;
sa->sin6.sin6_port = htons((uint16_t) port);
#endif
} else if (sscanf(str, "%u%n", &port, &len) == 1) {
// If only port is specified, bind to IPv4, INADDR_ANY
sa->sin.sin_port = htons((uint16_t) port);
port = 0; // Parsing failure. Make port invalid.
Sergey Lyubka
committed
return port <= 0xffff && str[len] == '\0';
const char *mg_set_option(struct mg_server *server, const char *name,
const char *value) {
int ind = get_option_index(name);
const char *error_msg = NULL;
if (ind < 0) {
error_msg = "No such option";
if (server->config_options[ind] != NULL) {
free(server->config_options[ind]);
}
server->config_options[ind] = mg_strdup(value);
if (ind == LISTENING_PORT) {
if (server->listening_sock != INVALID_SOCKET) {
closesocket(server->listening_sock);
}
parse_port_string(server->config_options[LISTENING_PORT], &server->lsa);
server->listening_sock = open_listening_socket(&server->lsa);
if (server->listening_sock == INVALID_SOCKET) {
error_msg = "Cannot bind to port";
Sergey Lyubka
committed
} else {
sockaddr_to_string(server->local_ip, sizeof(server->local_ip),
&server->lsa);
if (!strcmp(value, "0")) {
char buf[10];
mg_snprintf(buf, sizeof(buf), "%d",
(int) ntohs(server->lsa.sin.sin_port));
free(server->config_options[ind]);
server->config_options[ind] = mg_strdup(buf);
}
struct passwd *pw;
if ((pw = getpwnam(value)) == NULL) {
error_msg = "Unknown user";
} else if (setgid(pw->pw_gid) != 0) {
error_msg = "setgid() failed";
} else if (setuid(pw->pw_uid) != 0) {
error_msg = "setuid() failed";
}
} else if (ind == SSL_CERTIFICATE) {
if ((server->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
error_msg = "SSL_CTX_new() failed";
} else if (SSL_CTX_use_certificate_file(server->ssl_ctx, value, 1) == 0 ||
SSL_CTX_use_PrivateKey_file(server->ssl_ctx, value, 1) == 0) {
error_msg = "Cannot load PEM file";
} else {
SSL_CTX_use_certificate_chain_file(server->ssl_ctx, value);
}
void mg_set_http_error_handler(struct mg_server *server, mg_handler_t handler) {
server->error_handler = handler;
}
void mg_set_auth_handler(struct mg_server *server, mg_handler_t handler) {
server->auth_handler = handler;
}
Sergey Lyubka
committed
void mg_set_listening_socket(struct mg_server *server, int sock) {
if (server->listening_sock != INVALID_SOCKET) {
closesocket(server->listening_sock);
}
Sergey Lyubka
committed
}
int mg_get_listening_socket(struct mg_server *server) {
return server->listening_sock;
}
const char *mg_get_option(const struct mg_server *server, const char *name) {
const char **opts = (const char **) server->config_options;
int i = get_option_index(name);
return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
}
struct mg_server *mg_create_server(void *server_data) {
struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
#ifdef _WIN32
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
Sergey Lyubka
committed
#else
// Ignore SIGPIPE signal, so if browser cancels the request, it
// won't kill the whole process.
signal(SIGPIPE, SIG_IGN);
#endif
LINKED_LIST_INIT(&server->active_connections);
LINKED_LIST_INIT(&server->uri_handlers);
// Create control socket pair. Do it in a loop to protect from
// interrupted syscalls in mg_socketpair().
do {
mg_socketpair(server->ctl);
} while (server->ctl[0] == INVALID_SOCKET);
server->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#endif
server->server_data = server_data;
server->listening_sock = INVALID_SOCKET;
set_default_option_values(server->config_options);