Sun, 15 May 2022 08:56:00 +0200
make sure the http stream is finished if headers are sent
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "conf.h" #include <string.h> int cfg_parse_basic_file(ConfigParser *parser, FILE *in) { parser->lines = NULL; UcxMempool *mp = ucx_mempool_new(512); parser->mp = mp->allocator; // one logical line over many lines sstr_t mline; mline.ptr = NULL; mline.length = 0; ConfigLine *start_line; ConfigLine *end_line; // read file sstr_t l; while((l = cfg_readln(in)).ptr != NULL) { void *org_ptr = l.ptr; // put the line to the list ConfigLine *line = OBJ_NEW(parser->mp, ConfigLine); line->line = sstrdup_a(parser->mp, l); // TODO: check for 0-len str line->object = NULL; line->type = LINE_OTHER; if(parser->lines) { parser->lines = ucx_list_append_a(parser->mp, parser->lines, line); } else { parser->lines = ucx_list_append_a(parser->mp, parser->lines, line); } // check if the line contains something l = cfg_trim_comment(l); line->type = cfg_get_basic_type(l); if(line->type == LINE_OTHER) { // check for multi line if(mline.ptr != NULL) { // concate lines char *ptr = ucx_mempool_malloc( mp, mline.length + l.length + 1); memcpy(ptr, mline.ptr, mline.length); memcpy(ptr + mline.length - 1, l.ptr, l.length); mline.length += l.length; free(mline.ptr); mline.ptr = ptr; mline.ptr[mline.length] = 0; end_line = line; line->type = LINE_MULTI; } if(l.ptr[l.length - 1] == '\\') { if(mline.ptr == NULL) { mline = sstrdup_a(parser->mp, l); start_line = line; } } else { // this line is complete so we can parse it sstr_t ll; // we parse this line if(mline.ptr == NULL) { // single line ll = l; start_line = line; end_line = line; } else { ll = mline; } // parse int r = parser->parse(parser, start_line, end_line, ll); // clean up if(mline.ptr != NULL) { free(mline.ptr); mline.ptr = NULL; mline.length = 0; start_line = NULL; end_line = NULL; } if(r != 0) { free(org_ptr); return -1; } } } free(org_ptr); } return 0; } sstr_t cfg_readln(FILE *file) { sstr_t ns; ns.ptr = NULL; ns.length = 0; if(!feof(file)) { char buf[512]; buf[0] = 0; int len = 512; if(fgets(buf, len, file) == NULL) { return ns; } if(*buf == 0) { printf("???\n"); return ns; } char *ptr; if((ptr = strrchr(buf, '\n'))) { ptr[0] = 0; } sstr_t line = sstr(buf); return sstrdup(line); } sstr_t s; s.ptr = NULL; s.length = 0; return s; } /* * removes a comment from the line */ sstr_t cfg_trim_comment(sstr_t line) { sstr_t nl = line; for(int i=0;i<line.length;i++) { if(line.ptr[i] == '#') { if(i > 0) { nl.ptr = line.ptr + i - 1; nl.length = i; break; } else { nl.ptr = line.ptr; nl.length = 0; break; } } } return sstrtrim(nl); } /* * gets the first parameter in the params string and returns a new string * containing the other parameters or an empty string, if there are no more * parameters */ sstr_t cfg_param(sstr_t params, sstr_t *name, sstr_t *value) { name->ptr = NULL; name->length = 0; value->ptr = NULL; value->length = 0; // get name int i; for(i=0;i<params.length;i++) { char c = params.ptr[i]; if(c == '=') { break; } else if(c < 33) { // no '=' means there is only a name, no value name->ptr = params.ptr; name->length = i; params.ptr = params.ptr + i; params.length -= i; return sstrtrim(params); } } name->ptr = params.ptr; name->length = i; i++; // get value if(i>=params.length) { sstr_t ns; ns.ptr = NULL; ns.length = 0; return ns; } int quote = 0; value->ptr = params.ptr + i; for(;i<params.length;i++) { char c = params.ptr[i]; if(c == '"') { if(quote) { break; // end of quoted value } else { quote = 1; value->ptr++; } } else if(!quote && c < 33) { break; // end of value } } if(quote) { // if the value is quoted, i points to the last quote char value->length = i - name->length - 2; // subtract the quotes i++; // set i behind the last quote } else { // i points to a white space char, which must be subtraced value->length = i - name->length - 1; } if(value->length <= 0) { value->length = 0; value->ptr = NULL; } // create new params string params.ptr += i; params.length -= i; return sstrtrim(params); } /* * gets a value from a parameter */ sstr_t cfg_param_get(UcxList *list, sstr_t name) { while(list != NULL) { ConfigParam *param = list->data; if(!sstrcmp(param->name, name)) { return param->value; } list = list->next; } sstr_t ns; ns.ptr = NULL; ns.length = 0; return ns; } /* * parses a line containing a directive and returns a ConfigDirective object * or NULL if an error occurs */ ConfigDirective* cfg_parse_directive(sstr_t line, UcxAllocator *mp) { if(line.length < 6) { log_ereport(LOG_FAILURE, "cfg_parse_directive: line too short"); return NULL; // line too short } sstr_t name; int i; for(i=0;i<line.length;i++) { if(line.ptr[i] < 33) { break; } } name.ptr = line.ptr; name.length = i; // create directive object ConfigDirective *directive = OBJ_NEW(mp, ConfigDirective); directive->directive_type = sstrdup_a(mp, name); directive->type_num = cfg_get_directive_type_num(name); directive->condition = NULL; // set later by main parsing function //directive->param = NULL; sstr_t param_str; param_str.ptr = name.ptr + i; param_str.length = line.length - i; param_str = sstrtrim(param_str); directive->value = sstrdup_a(mp, param_str); /* sstr_t pname; sstr_t pvalue; for(;;) { param_str = cfg_param(param_str, &pname, &pvalue); if(pname.length <= 0) { break; } // create param object ConfigParam *param = OBJ_NEW(mp, ConfigParam); param->name = sstrdup_mp(mp, pname); if(pvalue.length > 0) { param->value = sstrdup_mp(mp, pvalue); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list //directive->param = ucx_list_append(directive->param, param); } */ return directive; } UcxList* cfg_param_list(sstr_t param_str, UcxAllocator *mp) { sstr_t pname; sstr_t pvalue; UcxList *plist = NULL; for(;;) { param_str = cfg_param(param_str, &pname, &pvalue); if(pname.length <= 0) { break; } // create param object ConfigParam *param = OBJ_NEW(mp, ConfigParam); param->name = sstrdup_a(mp, pname); if(pvalue.length > 0) { param->value = sstrdup_a(mp, pvalue); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list plist = ucx_list_append_a(mp, plist, param); } return plist; } /* * gets the directive type number from a type string * valid types are: * AuthTrans 0 * NameTrans 1 * PathCheck 2 * ObjectType 3 * Service 4 * AddLog 5 * Init 6 */ int cfg_get_directive_type_num(sstr_t type) { /* get nsapi function type */ // TODO: replace hard coded numbers int dt = -1; if(sstrcmp(type, sstr("AuthTrans")) == 0) { dt = NSAPIAuthTrans; } else if(sstrcmp(type, sstr("NameTrans")) == 0) { dt = NSAPINameTrans; } else if(sstrcmp(type, sstr("PathCheck")) == 0) { dt = NSAPIPathCheck; } else if(sstrcmp(type, sstr("ObjectType")) == 0) { dt = NSAPIObjectType; } else if(sstrcmp(type, sstr("Service")) == 0) { dt = NSAPIService; } else if(sstrcmp(type, sstr("Error")) == 0) { dt = NSAPIError; } else if(sstrcmp(type, sstr("AddLog")) == 0) { dt = NSAPIAddLog; } else if(sstrcmp(type, sstr("Init")) == 0) { dt = INIT_DIRECTIVE; } return dt; } /* * checks if the line contains only a comment or space */ int cfg_get_basic_type(sstr_t line) { if(line.length == 0) { return LINE_NOCONTENT; } else if(line.ptr[0] == '#') { return LINE_NOCONTENT; } return LINE_OTHER; } /* * checks if the line contains a begin/end tag or a directive */ int cfg_get_line_type(sstr_t line) { if(line.length < 3) { // this line is to short to be correct return LINE_ERROR; } if(line.ptr[0] == '<') { // start or end tag // TODO: check for space between '<' and '/' if(line.ptr[1] == '/') { return LINE_END_TAG; } else { return LINE_BEGIN_TAG; } } else { return LINE_DIRECTIVE; } } int cfg_get_tag_type(sstr_t tag) { if(!sstrcmp(tag, sstr("Object"))) { return TAG_OBJECT; } else if(!sstrcmp(tag, sstr("If"))) { return TAG_IF; } else if(!sstrcmp(tag, sstr("ElseIf"))) { return TAG_ELSEIF; } else if(!sstrcmp(tag, sstr("Else"))) { return TAG_ELSE; } else if(!sstrcmp(tag, sstr("Client"))) { return TAG_CLIENT; } return -1; } /* * returns the name of the ending tag * on error, this functions returns a zero length string */ sstr_t cfg_get_end_tag_name(sstr_t line) { sstr_t ns; ns.ptr = NULL; ns.length = 0; if(line.length < 4) { // minimum of 4 chars: </a> return ns; } sstr_t name; name.ptr = line.ptr + 2; name.length = line.length - 3; // check for </ > frame if(line.ptr[0] != '<' || line.ptr[1] != '/' || line.ptr[line.length - 1] != '>') { return ns; } return sstrtrim(name); } ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxAllocator *mp) { if(line.length < 4) { return NULL; // this line can't contain a valid tag } if(line.ptr[0] != '<' || line.ptr[line.length - 1] != '>') { return NULL; // syntax error } sstr_t name; name.ptr = line.ptr + 1; int i; for(i=1;i<line.length - 1;i++) { if(line.ptr[i] < 33) { // char is space break; } } name.length = i - 1; if(name.length < 1) { return NULL; // syntax error } // create tag object ConfigTag *tag = OBJ_NEW(mp, ConfigTag); tag->name = sstrdup_a(mp, name); tag->param = NULL; // parse parameters sstr_t param_str; param_str.ptr = line.ptr + i; param_str.length = line.length - name.length - 2; param_str = sstrtrim(param_str); if(param_str.length == 0) { return tag; // no parameters } tag->param_str = sstrdup_a(mp, param_str); sstr_t pname; sstr_t pvalue; for(;;) { param_str = cfg_param(param_str, &pname, &pvalue); if(pname.length == 0) { break; } // create param object ConfigParam *param = OBJ_NEW(mp, ConfigParam); param->name = sstrdup_a(mp, pname); if(pvalue.length > 0) { param->value = sstrdup_a(mp, pvalue); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list tag->param = ucx_list_append_a(mp, tag->param, param); } return tag; } /* directive functions */ /* * gets a ConfigDirective with a specific name from a List of directives * returns a directive or NULL, if the directive cannot be found */ ConfigDirective* cfg_directivelist_get(UcxList *dirs, sstr_t name) { while(dirs != NULL) { ConfigDirective *d = dirs->data; if(d != NULL) { if(!sstrcmp(d->directive_type, name)) { return d; } } dirs = dirs->next; } return NULL; } sstr_t cfg_directivelist_get_str(UcxList *dirs, sstr_t name) { ConfigDirective *d = cfg_directivelist_get(dirs, name); if(d == NULL) { sstr_t n; n.ptr = NULL; n.length = 0; return n; } //return cfg_directive_pstr1(d); return d->value; } /* * returns the name of the first parameter of the directive * useful for 'name value' directives */ /* sstr_t cfg_directive_pstr1(ConfigDirective *dir) { if(dir->param == NULL) { fprintf(stderr, "%s", "Error: cfg_directive_pstr1: param is NULL\n"); sstr_t n; n.ptr = NULL; n.length = 0; return n; } ConfigParam *p = dir->param->data; return p->name; } */ static void cfg_list_free(void *list) { ucx_list_free(list); } static void cfg_map_free(void *map) { ucx_map_free(map); } void cfg_map_destr(UcxMempool *mp, UcxMap *map) { if(map) { ucx_mempool_reg_destr(mp, map, cfg_map_free); } }