1
0
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:
Lammert Bies
2016-12-10 22:33:01 +01:00
parent ce757a70e4
commit 985fd93aec
4 changed files with 161 additions and 115 deletions

View File

@@ -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
View 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 */

View File

@@ -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 );

View File

@@ -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 */