mirror of
https://github.com/lammertb/libhttp.git
synced 2026-01-27 08:02:47 +03:00
Moved put_file to own file
This commit is contained in:
1
Makefile
1
Makefile
@@ -78,6 +78,7 @@ LIB_SOURCES = src/libhttp.c \
|
||||
src/httplib_parse_net.c \
|
||||
src/httplib_process_new_connection.c \
|
||||
src/httplib_produce_socket.c \
|
||||
src/httplib_put_file.c \
|
||||
src/httplib_read_websocket.c \
|
||||
src/httplib_redirect_to_https_port.c \
|
||||
src/httplib_refresh_trust.c \
|
||||
|
||||
145
src/httplib_put_file.c
Normal file
145
src/httplib_put_file.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lammert Bies
|
||||
* Copyright (c) 2013-2016 the Civetweb developers
|
||||
* Copyright (c) 2004-2013 Sergey Lyubka
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "libhttp-private.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* void XX_httplib_put_file( struct mg_connection *conn, const char *path );
|
||||
*
|
||||
* The function XX_httplib_put_file() processes a file PUT request coming from
|
||||
* a remote client.
|
||||
*/
|
||||
|
||||
#if !defined(NO_FILES)
|
||||
|
||||
void XX_httplib_put_file( struct mg_connection *conn, const char *path ) {
|
||||
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
const char *range;
|
||||
int64_t r1;
|
||||
int64_t r2;
|
||||
int rc;
|
||||
char date[64];
|
||||
time_t curtime;
|
||||
|
||||
if (conn == NULL) return;
|
||||
|
||||
curtime = time( NULL );
|
||||
|
||||
if (XX_httplib_stat(conn, path, &file)) {
|
||||
/* File already exists */
|
||||
conn->status_code = 200;
|
||||
|
||||
if (file.is_directory) {
|
||||
/* This is an already existing directory,
|
||||
* so there is nothing to do for the server. */
|
||||
rc = 0;
|
||||
|
||||
} else {
|
||||
/* File exists and is not a directory. */
|
||||
/* Can it be replaced? */
|
||||
|
||||
if (file.membuf != NULL) {
|
||||
/* This is an "in-memory" file, that can not be replaced */
|
||||
XX_httplib_send_http_error( conn, 405, "Error: Put not possible\nReplacing %s is not supported", path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the server may write this file */
|
||||
if (access(path, W_OK) == 0) {
|
||||
/* Access granted */
|
||||
conn->status_code = 200;
|
||||
rc = 1;
|
||||
} else {
|
||||
XX_httplib_send_http_error( conn, 403, "Error: Put not possible\nReplacing %s is not allowed", path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* File should be created */
|
||||
conn->status_code = 201;
|
||||
rc = XX_httplib_put_dir(conn, path);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/* XX_httplib_put_dir returns 0 if path is a directory */
|
||||
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
|
||||
mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code));
|
||||
XX_httplib_send_no_cache_header(conn);
|
||||
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, XX_httplib_suggest_connection_header(conn));
|
||||
|
||||
/* Request to create a directory has been fulfilled successfully.
|
||||
* No need to put a file. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
/* XX_httplib_put_dir returns -1 if the path is too long */
|
||||
XX_httplib_send_http_error(conn, 414, "Error: Path too long\nput_dir(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == -2) {
|
||||
/* XX_httplib_put_dir returns -2 if the directory can not be created */
|
||||
XX_httplib_send_http_error(conn, 500, "Error: Can not create directory\nput_dir(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
/* A file should be created or overwritten. */
|
||||
if (!XX_httplib_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
||||
XX_httplib_fclose(&file);
|
||||
XX_httplib_send_http_error(conn, 500, "Error: Can not create file\nfopen(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
XX_httplib_fclose_on_exec(&file, conn);
|
||||
range = mg_get_header(conn, "Content-Range");
|
||||
r1 = r2 = 0;
|
||||
if (range != NULL && XX_httplib_parse_range_header(range, &r1, &r2) > 0) {
|
||||
conn->status_code = 206; /* Partial content */
|
||||
fseeko(file.fp, r1, SEEK_SET);
|
||||
}
|
||||
|
||||
if (!XX_httplib_forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
|
||||
/* XX_httplib_forward_body_data failed.
|
||||
* The error code has already been sent to the client,
|
||||
* and conn->status_code is already set. */
|
||||
XX_httplib_fclose(&file);
|
||||
return;
|
||||
}
|
||||
|
||||
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
|
||||
mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code));
|
||||
XX_httplib_send_no_cache_header(conn);
|
||||
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, XX_httplib_suggest_connection_header(conn));
|
||||
|
||||
XX_httplib_fclose(&file);
|
||||
|
||||
} /* XX_httplib_put_file */
|
||||
|
||||
#endif /* !NO_FILES */
|
||||
@@ -874,6 +874,7 @@ struct mg_connection * XX_httplib_fc( struct mg_context *ctx );
|
||||
void XX_httplib_fclose( struct file *filep );
|
||||
void XX_httplib_fclose_on_exec( struct file *filep, struct mg_connection *conn );
|
||||
int XX_httplib_fopen( const struct mg_connection *conn, const char *path, const char *mode, struct file *filep );
|
||||
int XX_httplib_forward_body_data( struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl );
|
||||
void XX_httplib_free_context( struct mg_context *ctx );
|
||||
int XX_httplib_get_first_ssl_listener_index( const struct mg_context *ctx );
|
||||
const char * XX_httplib_get_header( const struct mg_request_info *ri, const char *name );
|
||||
@@ -913,9 +914,11 @@ const char * XX_httplib_next_option( const char *list, struct vec *val, struct
|
||||
int XX_httplib_parse_http_headers( char **buf, struct mg_request_info *ri );
|
||||
int XX_httplib_parse_http_message( char *buf, int len, struct mg_request_info *ri );
|
||||
int XX_httplib_parse_net( const char *spec, uint32_t *net, uint32_t *mask );
|
||||
int XX_httplib_parse_range_header( const char *header, int64_t *a, int64_t *b );
|
||||
void XX_httplib_process_new_connection( struct mg_connection *conn );
|
||||
void XX_httplib_produce_socket( struct mg_context *ctx, const struct socket *sp );
|
||||
int XX_httplib_pull( FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout );
|
||||
int XX_httplib_put_dir( struct mg_connection *conn, const char *path );
|
||||
void XX_httplib_put_file( struct mg_connection *conn, const char *path );
|
||||
int XX_httplib_read_request( FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread );
|
||||
void XX_httplib_read_websocket( struct mg_connection *conn, mg_websocket_data_handler ws_data_handler, void *callback_data );
|
||||
|
||||
127
src/libhttp.c
127
src/libhttp.c
@@ -4860,10 +4860,11 @@ void XX_httplib_send_file_data( struct mg_connection *conn, struct file *filep,
|
||||
} /* XX_httplib_send_file_data */
|
||||
|
||||
|
||||
static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
|
||||
int XX_httplib_parse_range_header( const char *header, int64_t *a, int64_t *b ) {
|
||||
|
||||
return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
|
||||
}
|
||||
|
||||
} /* XX_httplib_parse_range_header */
|
||||
|
||||
|
||||
static void construct_etag(char *buf, size_t buf_len, const struct file *filep) {
|
||||
@@ -4950,7 +4951,7 @@ void XX_httplib_handle_static_file_request( struct mg_connection *conn, const ch
|
||||
/* If Range: header specified, act accordingly */
|
||||
r1 = r2 = 0;
|
||||
hdr = mg_get_header(conn, "Range");
|
||||
if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0
|
||||
if (hdr != NULL && (n = XX_httplib_parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0
|
||||
&& r2 >= 0) {
|
||||
/* actually, range requests don't play well with a pre-gzipped
|
||||
* file (since the range is specified in the uncompressed space) */
|
||||
@@ -5086,7 +5087,7 @@ void mg_send_mime_file2( struct mg_connection *conn, const char *path, const cha
|
||||
* Return -1 for if the path is too long.
|
||||
* Return -2 if path can not be created.
|
||||
*/
|
||||
static int put_dir(struct mg_connection *conn, const char *path) {
|
||||
int XX_httplib_put_dir( struct mg_connection *conn, const char *path ) {
|
||||
|
||||
char buf[PATH_MAX];
|
||||
const char *s;
|
||||
@@ -5117,7 +5118,8 @@ static int put_dir(struct mg_connection *conn, const char *path) {
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} /* XX_httplib_put_dir */
|
||||
|
||||
|
||||
void XX_httplib_remove_bad_file( const struct mg_connection *conn, const char *path ) {
|
||||
@@ -5142,7 +5144,7 @@ long long mg_store_body( struct mg_connection *conn, const char *path ) {
|
||||
return -11;
|
||||
}
|
||||
|
||||
ret = put_dir(conn, path);
|
||||
ret = XX_httplib_put_dir(conn, path);
|
||||
if (ret < 0) {
|
||||
/* -1 for path too long,
|
||||
* -2 for path can not be created. */
|
||||
@@ -5433,7 +5435,7 @@ int XX_httplib_is_not_modified( const struct mg_connection *conn, const struct f
|
||||
|
||||
|
||||
#if !defined(NO_CGI) || !defined(NO_FILES)
|
||||
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl) {
|
||||
int XX_httplib_forward_body_data( struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl ) {
|
||||
|
||||
const char *expect;
|
||||
const char *body;
|
||||
@@ -5512,7 +5514,8 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock,
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} /* XX_httplib_forward_body_data */
|
||||
#endif
|
||||
|
||||
#if !defined(NO_CGI)
|
||||
@@ -5839,7 +5842,7 @@ void XX_httplib_handle_cgi_request( struct mg_connection *conn, const char *prog
|
||||
|
||||
if ((conn->request_info.content_length > 0) || conn->is_chunked) {
|
||||
/* This is a POST/PUT request, or another request with body data. */
|
||||
if (!forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
|
||||
if (!XX_httplib_forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
|
||||
/* Error sending the body data */
|
||||
mg_cry(conn, "Error: CGI program \"%s\": Forward body data failed", prog);
|
||||
goto done;
|
||||
@@ -6003,110 +6006,4 @@ void XX_httplib_mkcol( struct mg_connection *conn, const char *path ) {
|
||||
|
||||
} /* XX_httplib_mkcol */
|
||||
|
||||
|
||||
void XX_httplib_put_file( struct mg_connection *conn, const char *path ) {
|
||||
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
const char *range;
|
||||
int64_t r1;
|
||||
int64_t r2;
|
||||
int rc;
|
||||
char date[64];
|
||||
time_t curtime;
|
||||
|
||||
if (conn == NULL) return;
|
||||
|
||||
curtime = time( NULL );
|
||||
|
||||
if (XX_httplib_stat(conn, path, &file)) {
|
||||
/* File already exists */
|
||||
conn->status_code = 200;
|
||||
|
||||
if (file.is_directory) {
|
||||
/* This is an already existing directory,
|
||||
* so there is nothing to do for the server. */
|
||||
rc = 0;
|
||||
|
||||
} else {
|
||||
/* File exists and is not a directory. */
|
||||
/* Can it be replaced? */
|
||||
|
||||
if (file.membuf != NULL) {
|
||||
/* This is an "in-memory" file, that can not be replaced */
|
||||
XX_httplib_send_http_error( conn, 405, "Error: Put not possible\nReplacing %s is not supported", path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the server may write this file */
|
||||
if (access(path, W_OK) == 0) {
|
||||
/* Access granted */
|
||||
conn->status_code = 200;
|
||||
rc = 1;
|
||||
} else {
|
||||
XX_httplib_send_http_error( conn, 403, "Error: Put not possible\nReplacing %s is not allowed", path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* File should be created */
|
||||
conn->status_code = 201;
|
||||
rc = put_dir(conn, path);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/* put_dir returns 0 if path is a directory */
|
||||
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
|
||||
mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code));
|
||||
XX_httplib_send_no_cache_header(conn);
|
||||
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, XX_httplib_suggest_connection_header(conn));
|
||||
|
||||
/* Request to create a directory has been fulfilled successfully.
|
||||
* No need to put a file. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
/* put_dir returns -1 if the path is too long */
|
||||
XX_httplib_send_http_error(conn, 414, "Error: Path too long\nput_dir(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == -2) {
|
||||
/* put_dir returns -2 if the directory can not be created */
|
||||
XX_httplib_send_http_error(conn, 500, "Error: Can not create directory\nput_dir(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
/* A file should be created or overwritten. */
|
||||
if (!XX_httplib_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
||||
XX_httplib_fclose(&file);
|
||||
XX_httplib_send_http_error(conn, 500, "Error: Can not create file\nfopen(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
|
||||
XX_httplib_fclose_on_exec(&file, conn);
|
||||
range = mg_get_header(conn, "Content-Range");
|
||||
r1 = r2 = 0;
|
||||
if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
|
||||
conn->status_code = 206; /* Partial content */
|
||||
fseeko(file.fp, r1, SEEK_SET);
|
||||
}
|
||||
|
||||
if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
|
||||
/* forward_body_data failed.
|
||||
* The error code has already been sent to the client,
|
||||
* and conn->status_code is already set. */
|
||||
XX_httplib_fclose(&file);
|
||||
return;
|
||||
}
|
||||
|
||||
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
|
||||
mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code));
|
||||
XX_httplib_send_no_cache_header(conn);
|
||||
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, XX_httplib_suggest_connection_header(conn));
|
||||
|
||||
XX_httplib_fclose(&file);
|
||||
|
||||
} /* XX_httplib_put_file */
|
||||
|
||||
#endif /* !NO_FILES */
|
||||
|
||||
Reference in New Issue
Block a user