From 22a718de33fef78bab33bc00e52cd230c22e1945 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 13 Jul 2013 00:08:00 +0000 Subject: http: pass "struct mog_fd *" more consistently in API This makes it easier to write tapsets which key objects by: PID,FD for uniqueness. This also avoids some mog_fd_of() calls. --- cmogstored.h | 2 +- http.c | 31 +++++++++++----------- http.h | 7 +++-- http_dav.c | 16 +++++------ http_get.c | 15 ++++++----- http_put.c | 86 +++++++++++++++++++++++++++++++++--------------------------- 6 files changed, 82 insertions(+), 75 deletions(-) diff --git a/cmogstored.h b/cmogstored.h index 2dffbb2..859236a 100644 --- a/cmogstored.h +++ b/cmogstored.h @@ -503,7 +503,7 @@ void mog_httpget_post_accept(int fd, struct mog_svc *, enum mog_next mog_http_queue_step(struct mog_fd *) MOG_CHECK; void mog_http_quit_step(struct mog_fd *); char *mog_http_path(struct mog_http *, char *buf); -void mog_http_reset(struct mog_http *); +void mog_http_reset(struct mog_fd *); void mog_http_unlink_ftmp(struct mog_http *); void mog_http_drop(struct mog_fd *); diff --git a/http.c b/http.c index d147eb1..7e35252 100644 --- a/http.c +++ b/http.c @@ -136,16 +136,18 @@ void mog_http_drop(struct mog_fd *mfd) } /* returns true if we can continue queue step, false if not */ -static enum mog_next http_wbuf_in_progress(struct mog_http *http) +static enum mog_next http_wbuf_in_progress(struct mog_fd *mfd) { + struct mog_http *http = &mfd->as.http; + assert(http->wbuf != MOG_WR_ERROR && "still active after write error"); - switch (mog_tryflush(mog_fd_of(http)->fd, &http->wbuf)) { + switch (mog_tryflush(mfd->fd, &http->wbuf)) { case MOG_WRSTATE_ERR: return MOG_NEXT_CLOSE; case MOG_WRSTATE_DONE: if (!http->_p.persistent) return MOG_NEXT_CLOSE; if (http->forward == NULL) - mog_http_reset(http); + mog_http_reset(mfd); assert(http->_p.buf_off == 0 && "bad offset"); return MOG_NEXT_ACTIVE; case MOG_WRSTATE_BUSY: @@ -200,7 +202,7 @@ static enum mog_next http_run(struct mog_fd *mfd, struct mog_rbuf *rbuf, TRACE(CMOGSTORED_HTTP_REQ_BEGIN(true)); http_defer_rbuf(http, rbuf, buf_len); - mog_http_reset(http); + mog_http_reset(mfd); } return MOG_NEXT_ACTIVE; } @@ -239,7 +241,7 @@ static enum mog_next __http_queue_step(struct mog_fd *mfd) assert(mfd->fd >= 0 && "http fd is invalid"); - if (http->wbuf) return http_wbuf_in_progress(http); + if (http->wbuf) return http_wbuf_in_progress(mfd); if (http->forward) return http_forward_in_progress(mfd, true); /* we may have pipelined data in http->rbuf */ @@ -312,10 +314,10 @@ parse: err507or400: if (errno == ERANGE) { - mog_http_resp(http, "507 Insufficient Storage", false); + mog_http_resp(mfd, "507 Insufficient Storage", false); } else { err400: - mog_http_resp(http, "400 Bad Request", false); + mog_http_resp(mfd, "400 Bad Request", false); } return MOG_NEXT_CLOSE; } @@ -438,15 +440,12 @@ char *mog_http_path(struct mog_http *http, char *buf) /* TODO: see if the iovec overheads of writev() is even worth it... */ -void -mog_http_resp0( - struct mog_http *http, - struct iovec *status, - bool alive) +void mog_http_resp0(struct mog_fd *mfd, struct iovec *status, bool alive) { struct iovec iov; struct mog_now *now; char *dst = iov.iov_base = mog_fsbuf_get(&iov.iov_len); + struct mog_http *http = &mfd->as.http; assert(status->iov_len * 2 + 1024 < iov.iov_len && "fsbuf too small"); @@ -471,12 +470,12 @@ mog_http_resp0( iov.iov_len = dst - (char *)iov.iov_base; assert(http->wbuf == NULL && "tried to write with wbuf"); - http->wbuf = mog_trywritev(mog_fd_of(http)->fd, &iov, 1); + http->wbuf = mog_trywritev(mfd->fd, &iov, 1); } /* call whenever we're ready to read the next HTTP request */ -void mog_http_reset(struct mog_http *http) +void mog_http_reset(struct mog_fd *mfd) { - tcp_push(mog_fd_of(http), true); - mog_http_reset_parser(http); + tcp_push(mfd, true); + mog_http_reset_parser(&mfd->as.http); } diff --git a/http.h b/http.h index 3064d6e..5dd3a30 100644 --- a/http.h +++ b/http.h @@ -1,9 +1,8 @@ #include "iov_str.h" -void mog_http_resp0( - struct mog_http *, struct iovec *status, bool alive); +void mog_http_resp0(struct mog_fd *, struct iovec *status, bool alive); -#define mog_http_resp(http,conststr,alive) do { \ +#define mog_http_resp(mfd,conststr,alive) do { \ struct iovec statustmp; \ IOV_STR(&statustmp, (conststr)); \ - mog_http_resp0((http), &statustmp, (alive)); \ + mog_http_resp0((mfd), &statustmp, (alive)); \ } while (0) diff --git a/http_dav.c b/http_dav.c index 8503d45..94e7773 100644 --- a/http_dav.c +++ b/http_dav.c @@ -15,7 +15,7 @@ void mog_http_delete(struct mog_fd *mfd, char *buf) char *path; if (mfd->fd_type == MOG_FD_TYPE_HTTPGET) { - mog_http_resp(http, "405 Method Not Allowed", true); + mog_http_resp(mfd, "405 Method Not Allowed", true); return; } @@ -26,7 +26,7 @@ void mog_http_delete(struct mog_fd *mfd, char *buf) rc = mog_unlink(http->svc, path); if (rc == 0) { - mog_http_resp(http, "204 No Content", true); + mog_http_resp(mfd, "204 No Content", true); return; } @@ -35,14 +35,14 @@ void mog_http_delete(struct mog_fd *mfd, char *buf) case EISDIR: case EACCES: forbidden: - mog_http_resp(http, "403 Forbidden", true); + mog_http_resp(mfd, "403 Forbidden", true); return; case ENOENT: - mog_http_resp(http, "404 Not Found", true); + mog_http_resp(mfd, "404 Not Found", true); return; } PRESERVE_ERRNO(do { - mog_http_resp(http, "500 Internal Server Error", true); + mog_http_resp(mfd, "500 Internal Server Error", true); } while(0)); } @@ -52,7 +52,7 @@ void mog_http_mkcol(struct mog_fd *mfd, char *buf) char *path; if (mfd->fd_type == MOG_FD_TYPE_HTTPGET) { - mog_http_resp(http, "405 Method Not Allowed", true); + mog_http_resp(mfd, "405 Method Not Allowed", true); return; } path = mog_http_path(http, buf); @@ -64,7 +64,7 @@ void mog_http_mkcol(struct mog_fd *mfd, char *buf) * this. */ if (path) - mog_http_resp(http, "400 Bad Request", true); + mog_http_resp(mfd, "400 Bad Request", true); else /* path traversal attack */ - mog_http_resp(http, "403 Forbidden", true); + mog_http_resp(mfd, "403 Forbidden", true); } diff --git a/http_get.c b/http_get.c index 45470e5..252ec5c 100644 --- a/http_get.c +++ b/http_get.c @@ -44,8 +44,9 @@ static ssize_t linux_sendfile(int sockfd, int filefd, off_t *off, size_t count) * so we won't hurt code maintainability by optimizing away snprintf() * ourselves. This function is ugly enough already */ -static off_t http_get_resp_hdr(struct mog_http *http, struct stat *sb) +static off_t http_get_resp_hdr(struct mog_fd *mfd, struct stat *sb) { + struct mog_http *http = &mfd->as.http; char *modified; void *buf; size_t len; @@ -176,7 +177,7 @@ bad_range: if (http->_p.http_method == MOG_HTTP_METHOD_HEAD) count = 0; - http->wbuf = mog_trysend(mog_fd_of(http)->fd, buf, len, (off_t)count); + http->wbuf = mog_trysend(mfd->fd, buf, len, (off_t)count); return (off_t)count; } @@ -219,7 +220,7 @@ void mog_http_get_open(struct mog_fd *mfd, char *buf) file->fsize = sb.st_size; } - len = http_get_resp_hdr(http, &sb); + len = http_get_resp_hdr(mfd, &sb); /* http->forward may be NULL even if file is set if we had an error */ if (http->wbuf == NULL && http->forward) { @@ -233,14 +234,14 @@ err: switch (errno) { case EACCES: forbidden: - mog_http_resp(http, "403 Forbidden", true); + mog_http_resp(mfd, "403 Forbidden", true); return; case ENOENT: - mog_http_resp(http, "404 Not Found", true); + mog_http_resp(mfd, "404 Not Found", true); return; } PRESERVE_ERRNO(do { - mog_http_resp(http, "500 Internal Server Error", true); + mog_http_resp(mfd, "500 Internal Server Error", true); } while(0)); } @@ -288,7 +289,7 @@ retry: done: mog_file_close(http->forward); if (http->_p.persistent) { - mog_http_reset(http); + mog_http_reset(mfd); return MOG_NEXT_ACTIVE; } return MOG_NEXT_CLOSE; diff --git a/http_put.c b/http_put.c index 56a6325..da21f64 100644 --- a/http_put.c +++ b/http_put.c @@ -12,8 +12,10 @@ static __thread struct { char state[128]; } rnd; -static void file_close_null(struct mog_http *http) +static void file_close_null(struct mog_fd *mfd) { + struct mog_http *http = &mfd->as.http; + if (http->forward == NULL) return; mog_http_unlink_ftmp(http); @@ -71,10 +73,10 @@ bool mog_http_write_full(struct mog_fd *file_mfd, char *buf, size_t buf_len) return false; } -#define stop(http,status) stop0((http),(status),sizeof(status)-1); +#define stop(mfd,status) stop0((mfd),(status),sizeof(status)-1); MOG_NOINLINE static enum mog_next -stop0(struct mog_http *http, const char *status, size_t status_len) +stop0(struct mog_fd *mfd, const char *status, size_t status_len) { if (status) { struct iovec iov; @@ -84,26 +86,26 @@ stop0(struct mog_http *http, const char *status, size_t status_len) iov.iov_base = deconst.out; iov.iov_len = status_len; - mog_http_resp0(http, &iov, false); + mog_http_resp0(mfd, &iov, false); } - file_close_null(http); + file_close_null(mfd); return MOG_NEXT_CLOSE; } MOG_NOINLINE static enum mog_next -write_err(struct mog_http *http, const char *default_msg) +write_err(struct mog_fd *mfd, const char *default_msg) { switch (errno) { case ERANGE: case ENOSPC: case EFBIG: - return stop(http, "507 Insufficient Storage"); + return stop(mfd, "507 Insufficient Storage"); } if (default_msg == NULL) default_msg = "500 Internal Server Error"; - return stop0(http, default_msg, strlen(default_msg)); + return stop0(mfd, default_msg, strlen(default_msg)); } static bool md5_ok(struct mog_http *http) @@ -142,31 +144,35 @@ static bool set_perms_commit(struct mog_http *http) return false; } -static void put_commit_resp(struct mog_http *http) +static void put_commit_resp(struct mog_fd *mfd) { + struct mog_http *http = &mfd->as.http; + if (md5_ok(http)) { /* true if there's no MD5, too */ if (set_perms_commit(http)) { - file_close_null(http); - mog_http_resp(http, "201 Created", true); + file_close_null(mfd); + mog_http_resp(mfd, "201 Created", true); } else { - file_close_null(http); - mog_http_resp(http, "500 Internal Server Error", false); + file_close_null(mfd); + mog_http_resp(mfd, "500 Internal Server Error", false); } } else { - file_close_null(http); - mog_http_resp(http, "400 Bad Request", true); + file_close_null(mfd); + mog_http_resp(mfd, "400 Bad Request", true); } } -static enum mog_next http_put_commit(struct mog_http *http) +static enum mog_next http_put_commit(struct mog_fd *mfd) { - put_commit_resp(http); + struct mog_http *http = &mfd->as.http; + + put_commit_resp(mfd); if (http->wbuf && http->wbuf != MOG_WR_ERROR) return MOG_NEXT_WAIT_WR; if (!http->_p.persistent || http->wbuf == MOG_WR_ERROR) return MOG_NEXT_CLOSE; - mog_http_reset(http); + mog_http_reset(mfd); return MOG_NEXT_ACTIVE; } @@ -196,8 +202,9 @@ static void stash_advance_rbuf(struct mog_http *http, char *buf, size_t buf_len) } static void -chunked_body_after_header(struct mog_http *http, char *buf, size_t buf_len) +chunked_body_after_header(struct mog_fd *mfd, char *buf, size_t buf_len) { + struct mog_http *http = &mfd->as.http; size_t tmpoff = http->_p.buf_off; mog_chunk_init(http); @@ -205,7 +212,7 @@ chunked_body_after_header(struct mog_http *http, char *buf, size_t buf_len) switch (mog_chunk_parse(http, buf, buf_len)) { case MOG_PARSER_ERROR: - (void)write_err(http, "400 Bad Request"); + (void)write_err(mfd, "400 Bad Request"); return; case MOG_PARSER_CONTINUE: assert(http->_p.chunk_state != MOG_CHUNK_STATE_DONE); @@ -227,7 +234,7 @@ chunked_body_after_header(struct mog_http *http, char *buf, size_t buf_len) http->_p.skip_rbuf_defer = 1; return; case MOG_CHUNK_STATE_DONE: - put_commit_resp(http); + put_commit_resp(mfd); assert(http->_p.buf_off > 0 && "http->_p.buf_off unset after chunk body done"); stash_advance_rbuf(http, buf, buf_len); @@ -237,8 +244,9 @@ chunked_body_after_header(struct mog_http *http, char *buf, size_t buf_len) } static void -identity_body_after_header(struct mog_http *http, char *buf, size_t buf_len) +identity_body_after_header(struct mog_fd *mfd, char *buf, size_t buf_len) { + struct mog_http *http = &mfd->as.http; size_t body_len = buf_len - http->_p.buf_off; char *body_ptr = buf + http->_p.buf_off; @@ -248,7 +256,7 @@ identity_body_after_header(struct mog_http *http, char *buf, size_t buf_len) return; http->_p.buf_off += body_len; if (!mog_http_write_full(http->forward, body_ptr, body_len)) - (void)write_err(http, NULL); + (void)write_err(mfd, NULL); } static bool lengths_ok(struct mog_http *http) @@ -361,7 +369,7 @@ void mog_http_put(struct mog_fd *mfd, char *buf, size_t buf_len) struct mog_file *file; if (mfd->fd_type == MOG_FD_TYPE_HTTPGET) { - mog_http_resp(http, "405 Method Not Allowed", false); + mog_http_resp(mfd, "405 Method Not Allowed", false); return; } @@ -372,7 +380,7 @@ void mog_http_put(struct mog_fd *mfd, char *buf, size_t buf_len) assert(path[0] == '/' && "bad path"); if (!lengths_ok(http)) { - write_err(http, "400 Bad Request"); + write_err(mfd, "400 Bad Request"); return; } @@ -397,25 +405,25 @@ void mog_http_put(struct mog_fd *mfd, char *buf, size_t buf_len) && "http->_p.buf_off is wrong"); if (http->_p.chunked) - chunked_body_after_header(http, buf, buf_len); + chunked_body_after_header(mfd, buf, buf_len); else - identity_body_after_header(http, buf, buf_len); + identity_body_after_header(mfd, buf, buf_len); return; err: switch (errno) { case EINVAL: - mog_http_resp(http, "400 Bad Request", false); + mog_http_resp(mfd, "400 Bad Request", false); return; case ENOENT: - mog_http_resp(http, "404 Not Found", false); + mog_http_resp(mfd, "404 Not Found", false); return; case EACCES: - mog_http_resp(http, "403 Forbidden", false); + mog_http_resp(mfd, "403 Forbidden", false); return; } syslog(LOG_ERR, "problem starting PUT for path=%s (%m)", path); - (void)write_err(http, NULL); + (void)write_err(mfd, NULL); } static unsigned last_data_recv(int fd) @@ -473,7 +481,7 @@ static enum mog_next identity_put_in_progress(struct mog_fd *mfd) if (http->_p.has_content_range) need += http->_p.range_beg; if (need == 0) - return http_put_commit(http); + return http_put_commit(mfd); buf = mog_fsbuf_get(&buf_len); again: @@ -484,10 +492,10 @@ retry: r = read(mfd->fd, buf, buf_len); if (r > 0) { if (!mog_http_write_full(http->forward, buf, r)) - return write_err(http, NULL); + return write_err(mfd, NULL); need -= r; if (need == 0) - return http_put_commit(http); + return http_put_commit(mfd); if (mog_ioq_contended()) return MOG_NEXT_WAIT_RD; @@ -502,7 +510,7 @@ retry: /* assume all read() errors mean socket is unwritable, too */ read_err_dbg(mfd, r); - return stop(http, NULL); + return stop(mfd, NULL); } static enum mog_next chunked_put_in_progress(struct mog_fd *mfd) @@ -539,7 +547,7 @@ again: if (r <= 0) goto read_err; if (!mog_http_write_full(http->forward, buf, r)) - return write_err(http, NULL); + return write_err(mfd, NULL); http->_p.content_len -= r; @@ -581,7 +589,7 @@ chunk_state_trailer: switch (mog_chunk_parse(http, buf, buf_len)) { case MOG_PARSER_ERROR: - return write_err(http, "400 Bad Request"); + return write_err(mfd, "400 Bad Request"); case MOG_PARSER_CONTINUE: assert(http->_p.chunk_state != MOG_CHUNK_STATE_DONE); case MOG_PARSER_DONE: @@ -610,7 +618,7 @@ chunk_state_trailer: assert(http->rbuf->rsize > 0 && http->_p.buf_off == 0 && "bad rbuf"); - return http_put_commit(http); + return http_put_commit(mfd); } } assert(0 && "compiler bug?"); @@ -625,7 +633,7 @@ read_err: } } read_err_dbg(mfd, r); - return stop(http, NULL); + return stop(mfd, NULL); } enum mog_next mog_http_put_in_progress(struct mog_fd *mfd) -- cgit v1.2.3-24-ge0c7