mirror of
https://github.com/cesanta/mongoose.git
synced 2025-06-13 05:12:51 +08:00
Added MG_RECV event and mg_send_file_data() func
This commit is contained in:
parent
e389e70d05
commit
bdb16c624c
@ -3,33 +3,27 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
struct file_data {
|
|
||||||
FILE *fp;
|
|
||||||
const char *data;
|
|
||||||
int data_len;
|
|
||||||
int written;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int handle_request(struct mg_connection *conn) {
|
static int handle_request(struct mg_connection *conn) {
|
||||||
const char *data;
|
|
||||||
int data_len;
|
|
||||||
char var_name[100], file_name[100], path[100];
|
|
||||||
|
|
||||||
if (strcmp(conn->uri, "/upload") == 0) {
|
if (strcmp(conn->uri, "/upload") == 0) {
|
||||||
if (mg_parse_multipart(conn->content, conn->content_len,
|
FILE *fp = (FILE *) conn->connection_param;
|
||||||
var_name, sizeof(var_name),
|
if (fp != NULL) {
|
||||||
file_name, sizeof(file_name),
|
fwrite(conn->content, 1, conn->content_len, fp); // Write last bits
|
||||||
&data, &data_len) > 0) {
|
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
|
||||||
struct file_data *p = (struct file_data *) malloc(sizeof(*p));
|
"Content-Type: text/plain\r\n"
|
||||||
snprintf(path, sizeof(path), "UPLOAD_%s", file_name);
|
"Connection: close\r\n\r\n"
|
||||||
p->fp = fopen(path, "wb");
|
"Written %ld of POST data to a temp file:\n\n",
|
||||||
p->data = data;
|
(long) ftell(fp));
|
||||||
p->data_len = data_len;
|
|
||||||
p->written = 0;
|
// Temp file will be destroyed after fclose(), do something with the
|
||||||
conn->connection_param = p;
|
// data here -- for example, parse it and extract uploaded files.
|
||||||
mg_send_header(conn, "Content-Type", "text/html");
|
// As an example, we just echo the whole POST buffer back to the client.
|
||||||
|
rewind(fp);
|
||||||
|
mg_send_file_data(conn, fileno(fp));
|
||||||
|
return MG_MORE; // Tell Mongoose reply is not completed yet
|
||||||
|
} else {
|
||||||
|
mg_printf_data(conn, "%s", "Had no data to write...");
|
||||||
|
return MG_TRUE; // Tell Mongoose we're done with this request
|
||||||
}
|
}
|
||||||
return MG_MORE; // Tell mongoose to keep this connection open
|
|
||||||
} else {
|
} else {
|
||||||
mg_printf_data(conn, "%s",
|
mg_printf_data(conn, "%s",
|
||||||
"<html><body>Upload example."
|
"<html><body>Upload example."
|
||||||
@ -42,34 +36,36 @@ static int handle_request(struct mg_connection *conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_poll(struct mg_connection *conn) {
|
// Mongoose sends MG_RECV for every received POST chunk.
|
||||||
struct file_data *p = (struct file_data *) conn->connection_param;
|
// When last POST chunk is received, Mongoose sends MG_REQUEST, then MG_CLOSE.
|
||||||
if (p != NULL) {
|
static int handle_recv(struct mg_connection *conn) {
|
||||||
// Write no more then 100 bytes in one go
|
FILE *fp = (FILE *) conn->connection_param;
|
||||||
int len = p->data_len - p->written;
|
|
||||||
int n = fwrite(p->data + p->written, 1, len > 100 ? 100 : len, p->fp);
|
|
||||||
if (n > 0) {
|
|
||||||
p->written += n;
|
|
||||||
mg_send_data(conn, " ", 1); // Send something back to wake up select()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If everything is written, close the connection
|
// Open temporary file where we going to write data
|
||||||
if (p->written >= p->data_len) {
|
if (fp == NULL && ((conn->connection_param = fp = tmpfile())) == NULL) {
|
||||||
mg_printf_data(conn, "Written %d bytes.", p->written);
|
return -1; // Close connection on error
|
||||||
fclose(p->fp);
|
|
||||||
free(p);
|
|
||||||
conn->connection_param = NULL;
|
|
||||||
return MG_TRUE; // Tell mongoose to close this connection
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return MG_FALSE; // Tell mongoose to keep this connection open
|
|
||||||
|
// Return number of bytes written to a temporary file: that is how many
|
||||||
|
// bytes we want to discard from the receive buffer
|
||||||
|
return fwrite(conn->content, 1, conn->content_len, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we free all allocated resources
|
||||||
|
static int handle_close(struct mg_connection *conn) {
|
||||||
|
if (conn->connection_param != NULL) {
|
||||||
|
fclose((FILE *) conn->connection_param);
|
||||||
|
conn->connection_param = NULL;
|
||||||
|
}
|
||||||
|
return MG_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
|
||||||
switch (ev) {
|
switch (ev) {
|
||||||
case MG_AUTH: return MG_TRUE;
|
case MG_AUTH: return MG_TRUE;
|
||||||
case MG_REQUEST: return handle_request(conn);
|
case MG_REQUEST: return handle_request(conn);
|
||||||
case MG_POLL: return handle_poll(conn);
|
case MG_RECV: return handle_recv(conn);
|
||||||
|
case MG_CLOSE: return handle_close(conn);
|
||||||
default: return MG_FALSE;
|
default: return MG_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
mongoose.c
41
mongoose.c
@ -1341,7 +1341,7 @@ struct connection {
|
|||||||
enum endpoint_type endpoint_type;
|
enum endpoint_type endpoint_type;
|
||||||
char *path_info;
|
char *path_info;
|
||||||
char *request;
|
char *request;
|
||||||
int64_t num_bytes_sent; // Total number of bytes sent
|
int64_t num_bytes_recv; // Total number of bytes received
|
||||||
int64_t cl; // Reply content length, for Range support
|
int64_t cl; // Reply content length, for Range support
|
||||||
int request_len; // Request length, including last \r\n after last header
|
int request_len; // Request length, including last \r\n after last header
|
||||||
};
|
};
|
||||||
@ -3111,18 +3111,22 @@ static void open_file_endpoint(struct connection *conn, const char *path,
|
|||||||
conn->endpoint_type = EP_NONE;
|
conn->endpoint_type = EP_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mg_send_file_data(struct mg_connection *c, int fd) {
|
||||||
|
struct connection *conn = MG_CONN_2_CONN(c);
|
||||||
|
conn->endpoint_type = EP_FILE;
|
||||||
|
conn->endpoint.fd = fd;
|
||||||
|
ns_set_close_on_exec(conn->endpoint.fd);
|
||||||
|
}
|
||||||
#endif // MONGOOSE_NO_FILESYSTEM
|
#endif // MONGOOSE_NO_FILESYSTEM
|
||||||
|
|
||||||
static void call_request_handler_if_data_is_buffered(struct connection *conn) {
|
static void call_request_handler_if_data_is_buffered(struct connection *conn) {
|
||||||
struct iobuf *loc = &conn->ns_conn->recv_iobuf;
|
|
||||||
struct mg_connection *c = &conn->mg_conn;
|
|
||||||
|
|
||||||
#ifndef MONGOOSE_NO_WEBSOCKET
|
#ifndef MONGOOSE_NO_WEBSOCKET
|
||||||
if (conn->mg_conn.is_websocket) {
|
if (conn->mg_conn.is_websocket) {
|
||||||
do { } while (deliver_websocket_frame(conn));
|
do { } while (deliver_websocket_frame(conn));
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if ((size_t) loc->len >= c->content_len &&
|
if (conn->num_bytes_recv >= (conn->cl + conn->request_len) &&
|
||||||
call_request_handler(conn) == MG_FALSE) {
|
call_request_handler(conn) == MG_FALSE) {
|
||||||
open_local_endpoint(conn, 1);
|
open_local_endpoint(conn, 1);
|
||||||
}
|
}
|
||||||
@ -4446,6 +4450,7 @@ static void do_proxy(struct connection *conn) {
|
|||||||
|
|
||||||
static void on_recv_data(struct connection *conn) {
|
static void on_recv_data(struct connection *conn) {
|
||||||
struct iobuf *io = &conn->ns_conn->recv_iobuf;
|
struct iobuf *io = &conn->ns_conn->recv_iobuf;
|
||||||
|
int n;
|
||||||
|
|
||||||
if (conn->endpoint_type == EP_PROXY) {
|
if (conn->endpoint_type == EP_PROXY) {
|
||||||
if (conn->endpoint.nc != NULL) do_proxy(conn);
|
if (conn->endpoint.nc != NULL) do_proxy(conn);
|
||||||
@ -4478,6 +4483,14 @@ static void on_recv_data(struct connection *conn) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (conn->endpoint_type == EP_USER) {
|
if (conn->endpoint_type == EP_USER) {
|
||||||
|
conn->mg_conn.content = io->buf;
|
||||||
|
conn->mg_conn.content_len = io->len;
|
||||||
|
n = call_user(conn, MG_RECV);
|
||||||
|
if (n < 0) {
|
||||||
|
conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
|
||||||
|
} else if ((size_t) n <= io->len) {
|
||||||
|
iobuf_remove(io, n);
|
||||||
|
}
|
||||||
call_request_handler_if_data_is_buffered(conn);
|
call_request_handler_if_data_is_buffered(conn);
|
||||||
}
|
}
|
||||||
#ifndef MONGOOSE_NO_DAV
|
#ifndef MONGOOSE_NO_DAV
|
||||||
@ -4499,7 +4512,7 @@ static void call_http_client_handler(struct connection *conn) {
|
|||||||
}
|
}
|
||||||
iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
|
iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
|
||||||
conn->mg_conn.status_code = 0;
|
conn->mg_conn.status_code = 0;
|
||||||
conn->cl = conn->num_bytes_sent = conn->request_len = 0;
|
conn->cl = conn->num_bytes_recv = conn->request_len = 0;
|
||||||
free(conn->request);
|
free(conn->request);
|
||||||
conn->request = NULL;
|
conn->request = NULL;
|
||||||
}
|
}
|
||||||
@ -4568,12 +4581,12 @@ static void log_access(const struct connection *conn, const char *path) {
|
|||||||
flockfile(fp);
|
flockfile(fp);
|
||||||
mg_parse_header(mg_get_header(&conn->mg_conn, "Authorization"), "username",
|
mg_parse_header(mg_get_header(&conn->mg_conn, "Authorization"), "username",
|
||||||
user, sizeof(user));
|
user, sizeof(user));
|
||||||
fprintf(fp, "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT,
|
fprintf(fp, "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d 0",
|
||||||
c->remote_ip, user[0] == '\0' ? "-" : user, date,
|
c->remote_ip, user[0] == '\0' ? "-" : user, date,
|
||||||
c->request_method ? c->request_method : "-",
|
c->request_method ? c->request_method : "-",
|
||||||
c->uri ? c->uri : "-", c->query_string ? "?" : "",
|
c->uri ? c->uri : "-", c->query_string ? "?" : "",
|
||||||
c->query_string ? c->query_string : "",
|
c->query_string ? c->query_string : "",
|
||||||
c->http_version, c->status_code, conn->num_bytes_sent);
|
c->http_version, c->status_code);
|
||||||
log_header(c, "Referer", fp);
|
log_header(c, "Referer", fp);
|
||||||
log_header(c, "User-Agent", fp);
|
log_header(c, "User-Agent", fp);
|
||||||
fputc('\n', fp);
|
fputc('\n', fp);
|
||||||
@ -4619,17 +4632,20 @@ static void close_local_endpoint(struct connection *conn) {
|
|||||||
iobuf_free(&conn->ns_conn->recv_iobuf);
|
iobuf_free(&conn->ns_conn->recv_iobuf);
|
||||||
free(conn->request);
|
free(conn->request);
|
||||||
free(conn->path_info);
|
free(conn->path_info);
|
||||||
|
conn->endpoint.nc = NULL;
|
||||||
|
conn->request = conn->path_info = NULL;
|
||||||
|
|
||||||
conn->endpoint_type = EP_NONE;
|
conn->endpoint_type = EP_NONE;
|
||||||
conn->cl = conn->num_bytes_sent = conn->request_len = 0;
|
conn->cl = conn->num_bytes_recv = conn->request_len = 0;
|
||||||
conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
|
conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
|
||||||
NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
|
NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
|
||||||
MG_HEADERS_SENT | MG_LONG_RUNNING);
|
MG_HEADERS_SENT | MG_LONG_RUNNING);
|
||||||
|
memset(c, 0, sizeof(*c));
|
||||||
|
#if 0
|
||||||
c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
|
c->num_headers = c->status_code = c->is_websocket = c->content_len = 0;
|
||||||
conn->endpoint.nc = NULL;
|
|
||||||
c->request_method = c->uri = c->http_version = c->query_string = NULL;
|
c->request_method = c->uri = c->http_version = c->query_string = NULL;
|
||||||
conn->request = conn->path_info = NULL;
|
|
||||||
memset(c->http_headers, 0, sizeof(c->http_headers));
|
memset(c->http_headers, 0, sizeof(c->http_headers));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (keep_alive) {
|
if (keep_alive) {
|
||||||
on_recv_data(conn); // Can call us recursively if pipelining is used
|
on_recv_data(conn); // Can call us recursively if pipelining is used
|
||||||
@ -4981,6 +4997,9 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NS_RECV:
|
case NS_RECV:
|
||||||
|
if (conn != NULL) {
|
||||||
|
conn->num_bytes_recv += * (int *) p;
|
||||||
|
}
|
||||||
if (nc->flags & NSF_ACCEPTED) {
|
if (nc->flags & NSF_ACCEPTED) {
|
||||||
on_recv_data(conn);
|
on_recv_data(conn);
|
||||||
#ifndef MONGOOSE_NO_CGI
|
#ifndef MONGOOSE_NO_CGI
|
||||||
|
@ -66,6 +66,9 @@ enum mg_event {
|
|||||||
MG_AUTH, // If callback returns MG_FALSE, authentication fails
|
MG_AUTH, // If callback returns MG_FALSE, authentication fails
|
||||||
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
|
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
|
||||||
MG_REPLY, // If callback returns MG_FALSE, Mongoose closes connection
|
MG_REPLY, // If callback returns MG_FALSE, Mongoose closes connection
|
||||||
|
MG_RECV, // Mongoose has received POST data chunk.
|
||||||
|
// Callback should return a number of bytes to discard from
|
||||||
|
// the receive buffer, or -1 to close the connection.
|
||||||
MG_CLOSE, // Connection is closed, callback return value is ignored
|
MG_CLOSE, // Connection is closed, callback return value is ignored
|
||||||
MG_WS_HANDSHAKE, // New websocket connection, handshake request
|
MG_WS_HANDSHAKE, // New websocket connection, handshake request
|
||||||
MG_WS_CONNECT, // New websocket connection established
|
MG_WS_CONNECT, // New websocket connection established
|
||||||
@ -112,6 +115,7 @@ size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
|
|||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
|
|
||||||
void mg_send_file(struct mg_connection *, const char *path);
|
void mg_send_file(struct mg_connection *, const char *path);
|
||||||
|
void mg_send_file_data(struct mg_connection *, int fd);
|
||||||
|
|
||||||
const char *mg_get_header(const struct mg_connection *, const char *name);
|
const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||||
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
|
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
|
||||||
|
Loading…
Reference in New Issue
Block a user