void CMailMessage::FormatMessage() { start_header(); prepare_header(); end_header(); prepare_body(); }
static void answer_appropriate(struct vmod_fsdirector_file_system *fs) { unsigned available; char *url; char *url_start; char *url_end; size_t url_len; size_t root_len; char *path; struct stat stat_buf; if (strncmp("GET ", fs->htc.ws->s, 4)) { prepare_answer(&fs->htc, 405); prepare_body(&fs->htc); return; } url_start = &fs->htc.ws->s[4]; url_end = strchr(url_start, ' '); url_len = (url_end - url_start) + strlen(fs->root) + 1; url = WS_Alloc(fs->htc.ws, url_len); snprintf(url, url_len, "%s%s", fs->root, url_start); path = url; if (lstat(path, &stat_buf) < 0) { handle_file_error(&fs->htc, errno); return; } answer_file(fs, &stat_buf, path); }
static void send_response(struct vmod_fsdirector_file_system *fs, struct stat *stat_buf, const char *path) { int fd; off_t offset = 0; ssize_t remaining = stat_buf->st_size; ssize_t written; fd = open(path, O_RDONLY); if(fd < 0) { handle_file_error(&fs->htc, errno); return; } prepare_answer(&fs->htc, 200); dprintf(fs->htc.fd, "Content-Length: %lu\r\n", stat_buf->st_size); add_content_type(fs, path); prepare_body(&fs->htc); while (remaining > 0) { written = sendfile(fs->htc.fd, fd, &offset, remaining); if (written < 0) { perror("sendfile"); break; } remaining -= written; } // XXX too late for a 500 response... close(fd); }
static void send_redirect(struct vmod_fsdirector_file_system *fs, const char *path) { int link_buf_size; char link_buf[4096]; // XXX hardcoded const char *absolute_link; char const *location; link_buf_size = readlink(path, link_buf, 4096); if(link_buf_size < 0) { handle_file_error(&fs->htc, errno); return; } if (link_buf[0] != '/') { absolute_link = absolutize_link(fs->htc.ws, path, link_buf); if (absolute_link == NULL) { prepare_answer(&fs->htc, 500); prepare_body(&fs->htc); return; } } else { absolute_link = link_buf; } location = normalize_link(fs, absolute_link); if (location == NULL) { prepare_answer(&fs->htc, 500); prepare_body(&fs->htc); return; } prepare_answer(&fs->htc, 302); dprintf(fs->htc.fd, "Location: %s\r\n", location); prepare_body(&fs->htc); }
/* * macroend_bind * * Lexical binding for the special MACROEND lexeme type. No quotelevel/quotemodifier/cond * checks here. */ static int macroend_bind (lexctx_t lctx, void *ctx, quotelevel_t ql, quotemodifier_t qm, lextype_t lt, condstate_t cs, lexeme_t *lex, lexseq_t *result) { macroctx_t mctx = ctx; expansion_t *cur = mctx->curexp; expr_ctx_t ectx = mctx->ectx; parse_ctx_t pctx = expr_parse_ctx(ectx); struct macrodecl_s *curmac; lexeme_free(lctx, lex); if (cur == 0) { expr_signal(mctx->ectx, STC__INTCMPERR, "macroend_bind"); return 1; } curmac = name_extraspace(cur->curmacro); switch (mctx->state) { case EXP_EXITMACRO: lexseq_free(lctx, &cur->remaining); // FALLTHROUGH case EXP_EXITITER: case EXP_NORMAL: if (curmac->type == MACRO_ITER && lexseq_length(&cur->remaining) > 0) { if (cur->sep != 0) { lexseq_instail(result, lexeme_copy(lctx, cur->sep)); } mctx->state = EXP_NORMAL; parser_skipmode_set(pctx, 0); return prepare_body(mctx, cur, result); } if (curmac->type == MACRO_ITER && cur->closer != 0) { lexseq_instail(result, cur->closer); } // FALLTHROUGH case EXP_ERRORMACRO: mctx->curexp = cur->next; expansion_free(mctx, cur); if (mctx->state != EXP_ERRORMACRO || mctx->curexp == 0) { parser_skipmode_set(pctx, 0); } break; } mctx->state = EXP_NORMAL; return 1; } /* macroend_bind */
static void * server_bgthread(struct worker *wrk, void *priv) { struct vmod_fsdirector_file_system *fs; struct sockaddr_storage addr_s; socklen_t len; struct http_conn *htc; int fd; enum htc_status_e htc_status; CAST_OBJ_NOTNULL(fs, priv, VMOD_FSDIRECTOR_MAGIC); assert(fs->sock >= 0); htc = &fs->htc; fs->wrk = wrk; WS_Init(wrk->aws, fs->ws_name, malloc(WS_LEN), WS_LEN); while (1) { do { fd = accept(fs->sock, (void*)&addr_s, &len); } while (fd < 0 && errno == EAGAIN); if (fd < 0) { continue; } HTTP1_Init(htc, wrk->aws, fd, NULL, HTTP1_BUF, HTTP1_MAX_HDR); htc_status = HTTP1_Rx(htc); switch (htc_status) { case HTTP1_OVERFLOW: case HTTP1_ERROR_EOF: case HTTP1_ALL_WHITESPACE: case HTTP1_NEED_MORE: prepare_answer(htc, 400); prepare_body(htc); break; case HTTP1_COMPLETE: answer_appropriate(fs); break; } WS_Reset(wrk->aws, NULL); close(fd); } pthread_exit(0); NEEDLESS_RETURN(NULL); }
static void answer_file(struct vmod_fsdirector_file_system *fs, struct stat *stat_buf, const char *path) { mode_t mode = stat_buf->st_mode; if (S_ISREG(mode)) { if (stat_buf->st_size) { send_response(fs, stat_buf, path); } else { prepare_answer(&fs->htc, 204); prepare_body(&fs->htc); } } else if (S_ISLNK(mode)) { send_redirect(fs, path); } else { prepare_answer(&fs->htc, 404); prepare_body(&fs->htc); } }
static void handle_file_error(struct http_conn *htc, int err) { int status; switch (err) { case EACCES: status = 403; break; case ENAMETOOLONG: case EFAULT: status = 400; break; case ENOENT: case ENOTDIR: status = 404; break; default: status = 500; } prepare_answer(htc, status); prepare_body(htc); }
/* * macro_expand * * Expands a macro. */ static int macro_expand (macroctx_t mctx, name_t *macroname, lexseq_t *result) { struct macrodecl_s *macro = name_extraspace(macroname); expr_ctx_t ctx = mctx->ectx; parse_ctx_t pctx = expr_parse_ctx(ctx); lexctx_t lctx = parser_lexmemctx(pctx); expansion_t *curexp = expansion_alloc(mctx); expansion_t *prev_exp; lextype_t lt; lexeme_t *lex; lexseq_t extras; name_t *np; scopectx_t expscope; int which; int nactuals; punctclass_t pcl; lextype_t psep; lextype_t terms[3]; static strdesc_t comma = STRDEF(","); if (macro == 0 || curexp == 0) { expr_signal(ctx, STC__INTCMPERR, "macro_expand"); return 1; } memset(curexp, 0, sizeof(struct expansion_s)); // We save the punctuation class here, since it will get // munged by the parsing of the macro parameters. parser_punctclass_get(pctx, &pcl, &psep); prev_exp = 0; if (macro->type == MACRO_COND) { for (prev_exp = mctx->curexp; prev_exp != 0 && prev_exp->curmacro != macroname; prev_exp = prev_exp->next); } nactuals = 0; lexseq_init(&extras); // Simple macros with no formal arguments get no processing // of parameter lists whatsoever. if (macro->type == MACRO_SIMPLE && namereflist_length(¯o->plist) == 0) { expscope = 0; which = 3; } else { // For keyword macros, prime the scope with the declared // formals, so we can inherit the default values. if (macro->type == MACRO_KWD) { expscope = scope_copy(macro->ptable, 0); } else { expscope = scope_begin(scope_namectx(parser_scope_get(pctx)), 0); } lt = parser_next(pctx, QL_NORMAL, &lex); if (macro->type == MACRO_KWD) { if (lt != LEXTYPE_DELIM_LPAR) { expr_signal(ctx, STC__DELIMEXP, "("); parser_insert(pctx, lex); return 1; } which = 0; lexeme_free(lctx, lex); } else { for (which = 0; lt != openers[which] && which < 3; which++); if (which >= 3 && namereflist_length(¯o->plist) > 0) { expr_signal(ctx, STC__DELIMEXP, "("); parser_insert(pctx, lex); return 1; } if (which >= 3) { parser_insert(pctx, lex); } else { lexeme_free(lctx, lex); } } } // If we had a match on an opener, process // the actual parameters. if (which < 3) { nameref_t *formal; lexseq_t val; terms[0] = LEXTYPE_DELIM_COMMA; terms[1] = closers[which]; formal = namereflist_head(¯o->plist); while (1) { // Keyword macro actuals are of the form name=value // For positionals, grab the next formal-parameter name, // or set np to NULL to add the actual to %REMAINING. if (macro->type == MACRO_KWD) { lt = parser_next(pctx, QL_NAME, &lex); if (lexeme_boundtype(lex) != LEXTYPE_NAME) { expr_signal(ctx, STC__NAMEEXP); lexeme_free(lctx, lex); break; } np = name_search(macro->ptable, lex->text.ptr, lex->text.len, 0); if (np == 0) { expr_signal(ctx, STC__INTCMPERR, "macro_expand[2]"); } lexeme_free(lctx, lex); if (!parser_expect(pctx, QL_NORMAL, LEXTYPE_OP_ASSIGN, 0, 1)) { expr_signal(ctx, STC__OPEREXP, "="); break; } } else if (nactuals < namereflist_length(¯o->plist)) { np = formal->np; formal = formal->tq_next; } else { np = 0; } lexseq_init(&val); // Now parse the actual-parameter, which can be an expression if (!parse_lexeme_seq(pctx, 0, QL_NAME, terms, 2, &val, <)) { lexseq_free(lctx, &val); break; } // If we are recursively expanding a conditional macro and // there are no parameters, we're done - no expansion. if (prev_exp != 0 && lexseq_length(&val) == 0 && nactuals == 0) { scope_end(expscope); free(curexp); return 1; } if (np == 0) { if (lexseq_length(&extras) > 0) { lexseq_instail(&extras, lexeme_create(lctx, LEXTYPE_DELIM_COMMA, &comma)); } lexseq_append(&extras, &val); } else { name_t *actual; // Associate the actual with the formal. For keyword // macros, the scope_copy() above sets a special "no check" // flag that allows each name to be redeclared once. // name_declare() clears this flag, so we can catch genuine // redeclarations. actual = macparam_special(expscope, name_string(np), &val); if (actual == 0) { expr_signal(ctx, STC__INTCMPERR, "macro_expand[3]"); } lexseq_free(lctx, &val); } nactuals += 1; if (lt == closers[which]) { break; } if (lt != LEXTYPE_DELIM_COMMA) { expr_signal(ctx, STC__DELIMEXP, ","); break; } } /* while (1) */ if (lt != closers[which]) { expr_signal(ctx, STC__DELIMEXP, "closer"); lexseq_free(lctx, &extras); scope_end(expscope); return 1; } if (nactuals < namereflist_length(¯o->plist)) { name_t *anp; while (formal != 0) { anp = macparam_special(expscope, name_string(formal->np), 0); if (anp == 0) { expr_signal(ctx, STC__INTCMPERR, "macro_expand[4]"); } formal = formal->tq_next; } } } /* if which < 3 */ // The macro actual parameters are now processed; hook // the scope into the current hierarchy, restore the punctuation // class to what it was before we parsed the actuals, and // generate the expansion sequence. parser_punctclass_set(pctx, pcl, psep); curexp->count = (prev_exp == 0 ? 0 : prev_exp->count); curexp->expscope = expscope; curexp->curmacro = macroname; curexp->next = mctx->curexp; curexp->nactuals = nactuals; lexseq_append(&curexp->remaining, &extras); mctx->curexp = curexp; return prepare_body(mctx, curexp, result); } /* macro_expand */
inline size_t request::consume(char const * buf, size_t len) { size_t bytes_processed; if (m_ready) {return 0;} if (m_body_bytes_needed > 0) { bytes_processed = process_body(buf,len); if (body_ready()) { m_ready = true; } return bytes_processed; } // copy new header bytes into buffer m_buf->append(buf,len); // Search for delimiter in buf. If found read until then. If not read all std::string::iterator begin = m_buf->begin(); std::string::iterator end; for (;;) { // search for line delimiter end = std::search( begin, m_buf->end(), header_delimiter, header_delimiter+sizeof(header_delimiter)-1 ); m_header_bytes += (end-begin+sizeof(header_delimiter)); if (m_header_bytes > max_header_size) { // exceeded max header size throw exception("Maximum header size exceeded.", status_code::request_header_fields_too_large); } if (end == m_buf->end()) { // we are out of bytes. Discard the processed bytes and copy the // remaining unprecessed bytes to the beginning of the buffer std::copy(begin,end,m_buf->begin()); m_buf->resize(static_cast<std::string::size_type>(end-begin)); m_header_bytes -= m_buf->size(); return len; } //the range [begin,end) now represents a line to be processed. if (end-begin == 0) { // we got a blank line if (m_method.empty() || get_header("Host") == "") { throw exception("Incomplete Request",status_code::bad_request); } bytes_processed = ( len - static_cast<std::string::size_type>(m_buf->end()-end) + sizeof(header_delimiter) - 1 ); // frees memory used temporarily during request parsing m_buf.reset(); // if this was not an upgrade request and has a content length // continue capturing content-length bytes and expose them as a // request body. if (prepare_body()) { bytes_processed += process_body(buf+bytes_processed,len-bytes_processed); if (body_ready()) { m_ready = true; } return bytes_processed; } else { m_ready = true; // return number of bytes processed (starting bytes - bytes left) return bytes_processed; } } else { if (m_method.empty()) { this->process(begin,end); } else { this->process_header(begin,end); } } begin = end+(sizeof(header_delimiter)-1); } }