Esempio n. 1
0
void http_auth_setenv(array *env, const char *username, size_t ulen, const char *auth_type, size_t alen) {
    data_string *ds;

    /* REMOTE_USER */

    if (NULL == (ds = (data_string *)array_get_element(env, "REMOTE_USER"))) {
        if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
            ds = data_string_init();
        }
        buffer_copy_string_len(ds->key, CONST_STR_LEN("REMOTE_USER"));
        array_insert_unique(env, (data_unset *)ds);
    }
    buffer_copy_string_len(ds->value, username, ulen);

    /* AUTH_TYPE */

    if (NULL == (ds = (data_string *)array_get_element(env, "AUTH_TYPE"))) {
        if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
            ds = data_string_init();
        }
        buffer_copy_string_len(ds->key, CONST_STR_LEN("AUTH_TYPE"));
        array_insert_unique(env, (data_unset *)ds);
    }
    buffer_copy_string_len(ds->value, auth_type, alen);
}
Esempio n. 2
0
static int mod_evhost_parse_host(connection *con,array *host) {
	/* con->uri.authority->used is always > 0 if we come here */
	register char *ptr = con->uri.authority->ptr + con->uri.authority->used - 1;
	char *colon = ptr; /* needed to filter out the colon (if exists) */
	int first = 1;
	data_string *ds;
	int i;

	/* first, find the domain + tld */
	for(;ptr > con->uri.authority->ptr;ptr--) {
		if(*ptr == '.') {
			if(first) first = 0;
			else      break;
		} else if(*ptr == ':') {
			colon = ptr;
			first = 1;
		}
	}

	ds = data_string_init();
	buffer_copy_string_len(ds->key,CONST_STR_LEN("%0"));

	/* if we stopped at a dot, skip the dot */
	if (*ptr == '.') ptr++;
	buffer_copy_string_len(ds->value, ptr, colon-ptr);

	array_insert_unique(host,(data_unset *)ds);

	/* if the : is not the start of the authority, go on parsing the hostname */

	if (colon != con->uri.authority->ptr) {
		for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
			if(*ptr == '.') {
				if (ptr != colon - 1) {
					/* is something between the dots */
					ds = data_string_init();
					buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
					buffer_append_long(ds->key, i++);
					buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);

					array_insert_unique(host,(data_unset *)ds);
				}
				colon = ptr;
			}
		}

		/* if the . is not the first charactor of the hostname */
		if (colon != ptr) {
			ds = data_string_init();
			buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
			buffer_append_long(ds->key, i /* ++ */);
			buffer_copy_string_len(ds->value,ptr,colon-ptr);

			array_insert_unique(host,(data_unset *)ds);
		}
	}

	return 0;
}
Esempio n. 3
0
static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
  if (isnew) {
    dc->context_ndx = ctx->all_configs->used;
    assert(dc->context_ndx > ctx->current->context_ndx);
    array_insert_unique(ctx->all_configs, (data_unset *)dc);
    dc->parent = ctx->current;
    array_insert_unique(dc->parent->childs, (data_unset *)dc);
  }
  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
  ctx->current = dc;
}
Esempio n. 4
0
int main (int argc, char **argv) {
	array *a;
	data_string *ds;
	data_count *dc;

	UNUSED(argc);
	UNUSED(argv);

	a = array_init();

	ds = data_string_init();
	buffer_copy_string_len(ds->key, CONST_STR_LEN("abc"));
	buffer_copy_string_len(ds->value, CONST_STR_LEN("alfrag"));

	array_insert_unique(a, (data_unset *)ds);

	ds = data_string_init();
	buffer_copy_string_len(ds->key, CONST_STR_LEN("abc"));
	buffer_copy_string_len(ds->value, CONST_STR_LEN("hameplman"));

	array_insert_unique(a, (data_unset *)ds);

	ds = data_string_init();
	buffer_copy_string_len(ds->key, CONST_STR_LEN("123"));
	buffer_copy_string_len(ds->value, CONST_STR_LEN("alfrag"));

	array_insert_unique(a, (data_unset *)ds);

	dc = data_count_init();
	buffer_copy_string_len(dc->key, CONST_STR_LEN("def"));

	array_insert_unique(a, (data_unset *)dc);

	dc = data_count_init();
	buffer_copy_string_len(dc->key, CONST_STR_LEN("def"));

	array_insert_unique(a, (data_unset *)dc);

	array_print(a, 0);

	array_free(a);

	fprintf(stderr, "%d\n",
	       buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));

	return 0;
}
static void put_string_into_array_len(array *ary, const char *str, int len)
{
	data_string *tempdata;
	if (len == 0)
		return;
	tempdata = data_string_init();
	buffer_copy_string_len(tempdata->value,str,len);
	array_insert_unique(ary,(data_unset *)tempdata);
}
Esempio n. 6
0
static void proxy_append_header(connection *con, const char *key, const char *value) {
    data_string *ds_dst;

    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
          ds_dst = data_string_init();
    }

    buffer_copy_string(ds_dst->key, key);
    buffer_append_string(ds_dst->value, value);
    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
}
Esempio n. 7
0
/* replace or insert data, return the old one with the same key */
data_unset *array_replace(array *a, data_unset *du) {
	int ndx;

	if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
		array_insert_unique(a, du);
		return NULL;
	} else {
		data_unset *old = a->data[ndx];
		a->data[ndx] = du;
		return old;
	}
}
Esempio n. 8
0
static int ssi_env_add(array *env, const char *key, const char *val) {
	data_string *ds;

	if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
		ds = data_string_init();
	}
	buffer_copy_string(ds->key,   key);
	buffer_copy_string(ds->value, val);

	array_insert_unique(env, (data_unset *)ds);

	return 0;
}
int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
	data_string *ds;

	UNUSED(srv);

	if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
		ds = data_response_init();
	}
	buffer_copy_string_len(ds->key, key, keylen);
	buffer_copy_string_len(ds->value, value, vallen);

	array_insert_unique(con->response.headers, (data_unset *)ds);

	return 0;
}
Esempio n. 10
0
static int split_get_params(array *get_params, buffer *qrystr) {
	size_t is_key = 1;
	size_t i, len;
	char *key = NULL, *val = NULL;

	key = qrystr->ptr;

	/* we need the \0 */
	len = buffer_string_length(qrystr);
	for (i = 0; i <= len; i++) {
		switch(qrystr->ptr[i]) {
		case '=':
			if (is_key) {
				val = qrystr->ptr + i + 1;

				qrystr->ptr[i] = '\0';

				is_key = 0;
			}

			break;
		case '&':
		case '\0': /* fin symbol */
			if (!is_key) {
				data_string *ds;
				/* we need at least a = since the last & */

				/* terminate the value */
				qrystr->ptr[i] = '\0';

				if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
					ds = data_string_init();
				}
				buffer_copy_string_len(ds->key, key, strlen(key));
				buffer_copy_string_len(ds->value, val, strlen(val));

				array_insert_unique(get_params, (data_unset *)ds);
			}

			key = qrystr->ptr + i + 1;
			val = NULL;
			is_key = 1;
			break;
		}
	}

	return 0;
}
Esempio n. 11
0
data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
	data_integer *di;

	if (NULL == (di = (data_integer *)array_get_element_klen(srv->status, s, len))) {
		/* not found, create it */

		if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
			di = data_integer_init();
		}
		buffer_copy_string_len(di->key, s, len);
		di->value = 0;

		array_insert_unique(srv->status, (data_unset *)di);
	}
	return di;
}
Esempio n. 12
0
void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
	data_string *ds_dst;

	if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
		buffer_copy_string_len(ds_dst->value, value, val_len);
		return;
	}

	if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
		ds_dst = data_string_init();
	}

	buffer_copy_string_len(ds_dst->key, key, key_len);
	buffer_copy_string_len(ds_dst->value, value, val_len);
	array_insert_unique(hdrs, (data_unset *)ds_dst);
}
Esempio n. 13
0
/* op1 is to be eat/return by this function if success, op1->key is not cared
   op2 is left untouch, unreferenced
 */
data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
  /* type mismatch */
  if (op1->type != op2->type) {
    if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
      data_string *ds = (data_string *)op1;
      buffer_append_long(ds->value, ((data_integer*)op2)->value);
      return op1;
    } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
      data_string *ds = data_string_init();
      buffer_append_long(ds->value, ((data_integer*)op1)->value);
      buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
      op1->free(op1);
      return (data_unset *)ds;
    } else {
      fprintf(stderr, "data type mismatch, cannot be merge\n");
      return NULL;
    }
  }

  switch (op1->type) {
    case TYPE_STRING:
      buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
      break;
    case TYPE_INTEGER:
      ((data_integer *)op1)->value += ((data_integer *)op2)->value;
      break;
    case TYPE_ARRAY: {
      array *dst = ((data_array *)op1)->value;
      array *src = ((data_array *)op2)->value;
      data_unset *du;
      size_t i;

      for (i = 0; i < src->used; i ++) {
        du = (data_unset *)src->data[i];
        if (du) {
          array_insert_unique(dst, du->copy(du));
        }
      }
      break;
    default:
      assert(0);
      break;
    }
  }
  return op1;
}
LI_EXPORT int mod_proxy_backend_http_plugin_init(plugin *p) {
	data_string *ds;

	p->version      = LIGHTTPD_VERSION_ID;
	p->name         = buffer_init_string("mod_proxy_backend_http");

	p->init         = mod_proxy_backend_http_init;
	p->cleanup      = mod_proxy_backend_http_free;

	p->data         = NULL;

	ds = data_string_init();
	buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
	array_insert_unique(p->required_plugins, (data_unset *)ds);

	return 0;
}
Esempio n. 15
0
int http_response_insert_header(server *srv, connection *con, const char *key, size_t key_len
															, const char *value, size_t value_len)
{
	if (NULL == srv || NULL == con)
	{
		return -1;
	}
	
	if (NULL == key || 0 == key_len || NULL == value || 0 == value_len)
	{
		return -1;
	}
	
	if (NULL == con -> response.headers)
	{
		con -> response.headers = array_init();
	}
	
	data_string *ds = (data_string *)array_get_unused_element(con -> response.headers, TYPE_STRING);
	log_error_write(srv, __FILE__, __LINE__, "sd", "@@@@@@@@@@ get_unused_element: ", ds);
	if (NULL == ds)
	{
		ds = data_string_init();
		if(NULL == ds)
		{
			log_error_write(srv, __FILE__, __LINE__, "s", "Init data_string failed.");
			return -1;
		}
	}
	
	buffer_reset(ds -> value);
	buffer_reset(ds -> key);
	
	buffer_copy_string_len(ds -> key, key, key_len);
	buffer_copy_string_len(ds -> value, value, value_len);
	
	if ( -1 == array_insert_unique(con -> response.headers, (data_unset *)ds))
	{
		log_error_write(srv, __FILE__, __LINE__, "s", "Insert header failed.");
		return -1;
	}
	
	return 0;
}
Esempio n. 16
0
int main (int argc, char **argv) {
    char hostname[STD_BUFF_SIZE] = "";
    unsigned int port;
    char ch;
    data_string *ds;

    filter flt = {"", "", FALSE};
    
    array * arr = array_init();

    if (argc == 1) {
        show_help();
    }

    while((ch = getopt(argc, argv, "h:p:r:f:")) != -1) {
        switch (ch) {
            case 'h':
                ds = data_string_init();
                buffer_copy_string_len(ds->key, CONST_STR_LEN("HOSTNAME"));
                buffer_copy_string_len(ds->value, (const char *)optarg, strlen(optarg));
                array_insert_unique(arr, (data_unset *) ds);
                break;
            case 'p':
                port = (unsigned int) atoi((const char *) optarg);
                break;
            case 'r':
                //strcpy(hostname, optarg);
                parse_arguments_ip(arr, (const char *)optarg, strlen(optarg));
                break;
            case 'f':
                flt.re = optarg;
                flt.is_set = TRUE;
                break;
            default:
                show_help();
                break;
        }
    }

    task(arr, port, &flt);
    
    array_free(arr);
    return 0;
}
Esempio n. 17
0
int parse_arguments_ip(array *a, const char *ips, const int ips_len) {
    data_string *ds;
    char buf[16] = "";
    char tmp[16] = "";
    int i, j = 0;
    short min, max;
    int flag = 1;
    for (i = ips_len - 1; i >= 0; --i) {
        buf[j] =  ips[i];
        if (ips[i] == '-') {
            buf[j] = '\0';
            max = atoi(reverse(buf));
            memset(buf, '\0', strlen(buf));
            j = 0;
            continue;
        } else if (flag && ips[i] == '.') {
            buf[j] = '\0';
            min = atoi(reverse(buf));
            memset(buf, '\0', strlen(buf));
            flag = 0;
            j = 0;
            continue;
        }
        ++j;
    }
    j = min;
    reverse((char *) buf);
#ifdef DEBUG
    fprintf(stdout, "# Scan IP Range: %s.%d-%d #\n", buf, min, max);
#endif
    while (j < max) {
        ds = data_string_init();
        sprintf(tmp, "%s.%d", buf, j);
        buffer_copy_string_len(ds->value, (const char *)tmp, strlen(tmp));
        sprintf(tmp, "%d", j);
        buffer_copy_string_len(ds->key, (const char *)tmp, strlen(tmp));
        array_insert_unique(a, (data_unset *)ds);
        ++j;
    }
}
//该函数用于逐个记录那些被转换了的配置信息(记录在srv->config_touched中)
int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;
	//对将要被转换的配置值逐个判断以记录被使用了的配置项
	for (i = 0; cv[i].key; i++) {
		data_string *touched;

		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */
			//配置文件里没有对其的配置项
			continue;
		}

		/* touched */ //有配置
		touched = data_string_init();

		buffer_copy_string_len(touched->value, CONST_STR_LEN("")); //并不关心其配置值
		buffer_copy_string_buffer(touched->key, du->key); //获取其配置项的Key

		array_insert_unique(srv->config_touched, (data_unset *)touched); //记录被使用的配置项
	}

	return config_insert_values_internal(srv, ca, cv); //调用函数config_insert_values_internal()获取配置值
}
Esempio n. 19
0
int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
	size_t i;
	data_unset *du;

	for (i = 0; cv[i].key; i++) {
		data_string *touched;

		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */

			continue;
		}

		/* touched */
		touched = data_string_init();
		
		buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
		buffer_copy_buffer(touched->key, du->key);

		array_insert_unique(srv->config_touched, (data_unset *)touched);
	}
	
	return config_insert_values_internal(srv, ca, cv, scope);
}
Esempio n. 20
0
/* parse config array */
int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
	size_t i;
	data_unset *du;

	for (i = 0; cv[i].key; i++) {

		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */

			continue;
		}

		if ((T_CONFIG_SCOPE_SERVER == cv[i].scope)
		    && (T_CONFIG_SCOPE_SERVER != scope)) {
			/* server scope options should only be set in server scope, not in conditionals */
			log_error_write(srv, __FILE__, __LINE__, "ss",
				"DEPRECATED: don't set server options in conditionals, variable:",
				cv[i].key);
		}
		
		switch (cv[i].type) {
		case T_CONFIG_ARRAY:
			if (du->type == TYPE_ARRAY) {
				size_t j;
				data_array *da = (data_array *)du;

				for (j = 0; j < da->value->used; j++) {
					if (da->value->data[j]->type == TYPE_STRING) {
						data_string *ds = data_string_init();

						buffer_copy_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
						if (!da->is_index_key) {
							/* the id's were generated automaticly, as we copy now we might have to renumber them
							 * this is used to prepend server.modules by mod_indexfile as it has to be loaded
							 * before mod_fastcgi and friends */
							buffer_copy_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
						}

						array_insert_unique(cv[i].destination, (data_unset *)ds);
					} else {
						log_error_write(srv, __FILE__, __LINE__, "sssbsd",
								"the value of an array can only be a string, variable:",
								cv[i].key, "[", da->value->data[j]->key, "], type:", da->value->data[j]->type);

						return -1;
					}
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");

				return -1;
			}
			break;
		case T_CONFIG_STRING:
			if (du->type == TYPE_STRING) {
				data_string *ds = (data_string *)du;
				buffer_copy_buffer(cv[i].destination, ds->value);
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");

				return -1;
			}
			break;
		case T_CONFIG_SHORT:
			switch(du->type) {
			case TYPE_INTEGER: {
				data_integer *di = (data_integer *)du;

				*((unsigned short *)(cv[i].destination)) = di->value;
				break;
			}
			case TYPE_STRING: {
				data_string *ds = (data_string *)du;

				/* If the value came from an environment variable, then it is a
				 * data_string, although it may contain a number in ASCII
				 * decimal format.  We try to interpret the string as a decimal
				 * short before giving up, in order to support setting numeric
				 * values with environment variables (eg, port number).
				 */
				if (ds->value->ptr && *ds->value->ptr) {
					char *e;
					long l = strtol(ds->value->ptr, &e, 10);
					if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
						*((unsigned short *)(cv[i].destination)) = l;
						break;
					}
				}

				log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);

				return -1;
			}
			default:
				log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
				return -1;
			}
			break;
		case T_CONFIG_INT:
			switch(du->type) {
			case TYPE_INTEGER: {
				data_integer *di = (data_integer *)du;

				*((unsigned int *)(cv[i].destination)) = di->value;
				break;
			}
			case TYPE_STRING: {
				data_string *ds = (data_string *)du;

				if (ds->value->ptr && *ds->value->ptr) {
					char *e;
					long l = strtol(ds->value->ptr, &e, 10);
					if (e != ds->value->ptr && !*e && l >= 0) {
						*((unsigned int *)(cv[i].destination)) = l;
						break;
					}
				}

				log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);

				return -1;
			}
			default:
				log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
				return -1;
			}
			break;
		case T_CONFIG_BOOLEAN:
			if (du->type == TYPE_STRING) {
				data_string *ds = (data_string *)du;

				if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
					*((unsigned short *)(cv[i].destination)) = 1;
				} else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
					*((unsigned short *)(cv[i].destination)) = 0;
				} else {
					log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");

					return -1;
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");

				return -1;
			}
			break;
		case T_CONFIG_LOCAL:
		case T_CONFIG_UNSET:
			break;
		case T_CONFIG_UNSUPPORTED:
			log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));

			srv->config_unsupported = 1;

			break;
		case T_CONFIG_DEPRECATED:
			log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));

			srv->config_deprecated = 1;

			break;
		}
	}

	return 0;
}
Esempio n. 21
0
static void https_add_ssl_entries(connection *con) {
	X509 *xs;
	X509_NAME *xn;
	X509_NAME_ENTRY *xe;
	int i, nentries;

	if (
		SSL_get_verify_result(con->ssl) != X509_V_OK
		|| !(xs = SSL_get_peer_certificate(con->ssl))
	) {
		return;
	}

	xn = X509_get_subject_name(xs);
	for (i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
		int xobjnid;
		const char * xobjsn;
		data_string *envds;

		if (!(xe = X509_NAME_get_entry(xn, i))) {
			continue;
		}
		xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
		xobjsn = OBJ_nid2sn(xobjnid);
		if (!xobjsn) {
			continue;
		}

		if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
			envds = data_string_init();
		}
		buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
		buffer_append_string(envds->key, xobjsn);
		buffer_copy_string_len(
			envds->value,
			(const char *)xe->value->data, xe->value->length
		);
		/* pick one of the exported values as "authed user", for example
		 * ssl.verifyclient.username   = "******" or "SSL_CLIENT_S_DN_emailAddress"
		 */
		if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) {
			buffer_copy_string_buffer(con->authed_user, envds->value);
		}
		array_insert_unique(con->environment, (data_unset *)envds);
	}
	if (con->conf.ssl_verifyclient_export_cert) {
		BIO *bio;
		if (NULL != (bio = BIO_new(BIO_s_mem()))) {
			data_string *envds;
			int n;

			PEM_write_bio_X509(bio, xs);
			n = BIO_pending(bio);

			if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
				envds = data_string_init();
			}

			buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
			buffer_prepare_copy(envds->value, n+1);
			BIO_read(bio, envds->value->ptr, n);
			BIO_free(bio);
			envds->value->ptr[n] = '\0';
			envds->value->used = n+1;
			array_insert_unique(con->environment, (data_unset *)envds);
		}
	}
	X509_free(xs);
}
Esempio n. 22
0
static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
	size_t k;
	int auth_required = 0, auth_satisfied = 0;
	char *http_authorization = NULL;
	const char *auth_type = NULL;
	data_string *ds;
	mod_auth_plugin_data *p = p_d;
	array *req;
	data_string *req_method;

	/* select the right config */
	mod_auth_patch_connection(srv, con, p);

	if (p->conf.auth_require == NULL) return HANDLER_GO_ON;

	/*
	 * AUTH
	 *
	 */

	/* do we have to ask for auth ? */

	auth_required = 0;
	auth_satisfied = 0;

	/* search auth-directives for path */
	for (k = 0; k < p->conf.auth_require->used; k++) {
		buffer *require = p->conf.auth_require->data[k]->key;

		if (buffer_is_empty(require)) continue;
		if (buffer_string_length(con->uri.path) < buffer_string_length(require)) continue;

		/* if we have a case-insensitive FS we have to lower-case the URI here too */

		if (con->conf.force_lowercase_filenames) {
			if (0 == strncasecmp(con->uri.path->ptr, require->ptr, buffer_string_length(require))) {
				auth_required = 1;
				break;
			}
		} else {
			if (0 == strncmp(con->uri.path->ptr, require->ptr, buffer_string_length(require))) {
				auth_required = 1;
				break;
			}
		}
	}

	/* nothing to do for us */
	if (auth_required == 0) return HANDLER_GO_ON;

	req = ((data_array *)(p->conf.auth_require->data[k]))->value;
	req_method = (data_string *)array_get_element(req, "method");

	if (0 == strcmp(req_method->value->ptr, "extern")) {
		/* require REMOTE_USER to be already set */
		if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
			con->http_status = 401;
			con->mode = DIRECT;
			return HANDLER_FINISHED;
		} else if (http_auth_match_rules(srv, req, ds->value->ptr, NULL, NULL)) {
			log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
			con->http_status = 401;
			con->mode = DIRECT;
			return HANDLER_FINISHED;
		} else {
			return HANDLER_GO_ON;
		}
	}

	/* try to get Authorization-header */

	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization")) && !buffer_is_empty(ds->value)) {
		char *auth_realm;

		http_authorization = ds->value->ptr;

		/* parse auth-header */
		if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
			int auth_type_len = auth_realm - http_authorization;

			if ((auth_type_len == 5) &&
			    (0 == strncasecmp(http_authorization, "Basic", auth_type_len))) {
				auth_type = "Basic";

				if (0 == strcmp(req_method->value->ptr, "basic")) {
					auth_satisfied = http_auth_basic_check(srv, con, p, req, auth_realm+1);
				}
			} else if ((auth_type_len == 6) &&
				   (0 == strncasecmp(http_authorization, "Digest", auth_type_len))) {
				auth_type = "Digest";
				if (0 == strcmp(req_method->value->ptr, "digest")) {
					if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, auth_realm+1))) {
						con->http_status = 400;
						con->mode = DIRECT;

						/* a field was missing */

						return HANDLER_FINISHED;
					}
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ss",
						"unknown authentication type:",
						http_authorization);
			}
		}
	}

	if (!auth_satisfied) {
		data_string *method, *realm;
		method = (data_string *)array_get_element(req, "method");
		realm = (data_string *)array_get_element(req, "realm");

		con->http_status = 401;
		con->mode = DIRECT;

		if (0 == strcmp(method->value->ptr, "basic")) {
			buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Basic realm=\""));
			buffer_append_string_buffer(p->tmp_buf, realm->value);
			buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\""));

			response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
		} else if (0 == strcmp(method->value->ptr, "digest")) {
			char hh[33];
			http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, &hh);

			buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Digest realm=\""));
			buffer_append_string_buffer(p->tmp_buf, realm->value);
			buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", nonce=\""));
			buffer_append_string(p->tmp_buf, hh);
			buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", qop=\"auth\""));

			response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
		} else {
			/* evil */
		}
		return HANDLER_FINISHED;
	} else {
		/* the REMOTE_USER header */

		if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
			if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
				ds = data_string_init();
			}
			buffer_copy_string(ds->key, "REMOTE_USER");
			array_insert_unique(con->environment, (data_unset *)ds);
		}
		buffer_copy_buffer(ds->value, p->auth_user);

		/* AUTH_TYPE environment */

		if (NULL == (ds = (data_string *)array_get_element(con->environment, "AUTH_TYPE"))) {
			if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
				ds = data_string_init();
			}
			buffer_copy_string(ds->key, "AUTH_TYPE");
			array_insert_unique(con->environment, (data_unset *)ds);
		}
		buffer_copy_string(ds->value, auth_type);
	}

	return HANDLER_GO_ON;
}
Esempio n. 23
0
static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
	char *ns;
	const char *s;
	int line = 0;

	UNUSED(srv);

	buffer_copy_buffer(p->parse_response, in);

	for (s = p->parse_response->ptr;
	     NULL != (ns = strchr(s, '\n'));
	     s = ns + 1, line++) {
		const char *key, *value;
		int key_len;
		data_string *ds;

		/* strip the \n */
		ns[0] = '\0';

		if (ns > s && ns[-1] == '\r') ns[-1] = '\0';

		if (line == 0 &&
		    0 == strncmp(s, "HTTP/1.", 7)) {
			/* non-parsed header ... we parse them anyway */

			if ((s[7] == '1' ||
			     s[7] == '0') &&
			    s[8] == ' ') {
				int status;
				/* after the space should be a status code for us */

				status = strtol(s+9, NULL, 10);

				if (status >= 100 &&
				    status < 1000) {
					/* we expected 3 digits and didn't got them */
					con->parsed_response |= HTTP_STATUS;
					con->http_status = status;
				}
			}
		} else {
			/* parse the headers */
			key = s;
			if (NULL == (value = strchr(s, ':'))) {
				/* we expect: "<key>: <value>\r\n" */
				continue;
			}

			key_len = value - key;
			value += 1;

			/* skip LWS */
			while (*value == ' ' || *value == '\t') value++;

			if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
				ds = data_response_init();
			}
			buffer_copy_string_len(ds->key, key, key_len);
			buffer_copy_string(ds->value, value);

			array_insert_unique(con->response.headers, (data_unset *)ds);

			switch(key_len) {
			case 4:
				if (0 == strncasecmp(key, "Date", key_len)) {
					con->parsed_response |= HTTP_DATE;
				}
				break;
			case 6:
				if (0 == strncasecmp(key, "Status", key_len)) {
					int status = strtol(value, NULL, 10);
					if (status >= 100 && status < 1000) {
						con->http_status = status;
						con->parsed_response |= HTTP_STATUS;
					} else {
						con->http_status = 502;
					}
				}
				break;
			case 8:
				if (0 == strncasecmp(key, "Location", key_len)) {
					con->parsed_response |= HTTP_LOCATION;
				}
				break;
			case 10:
				if (0 == strncasecmp(key, "Connection", key_len)) {
					con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
					con->parsed_response |= HTTP_CONNECTION;
				}
				break;
			case 14:
				if (0 == strncasecmp(key, "Content-Length", key_len)) {
					con->response.content_length = strtoul(value, NULL, 10);
					con->parsed_response |= HTTP_CONTENT_LENGTH;
				}
				break;
			default:
				break;
			}
		}
	}

	/* CGI/1.1 rev 03 - 7.2.1.2 */
	if ((con->parsed_response & HTTP_LOCATION) &&
	    !(con->parsed_response & HTTP_STATUS)) {
		con->http_status = 302;
	}

	return 0;
}
Esempio n. 24
0
static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n, stat_cache_entry *sce) {
	size_t i, ssicmd = 0;
	char buf[255];
	buffer *b = NULL;

	struct {
		const char *var;
		enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
				SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
				SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
	} ssicmds[] = {
		{ "echo",     SSI_ECHO },
		{ "include",  SSI_INCLUDE },
		{ "flastmod", SSI_FLASTMOD },
		{ "fsize",    SSI_FSIZE },
		{ "config",   SSI_CONFIG },
		{ "printenv", SSI_PRINTENV },
		{ "set",      SSI_SET },
		{ "if",       SSI_IF },
		{ "elif",     SSI_ELIF },
		{ "endif",    SSI_ENDIF },
		{ "else",     SSI_ELSE },
		{ "exec",     SSI_EXEC },

		{ NULL, SSI_UNSET }
	};

	for (i = 0; ssicmds[i].var; i++) {
		if (0 == strcmp(l[1], ssicmds[i].var)) {
			ssicmd = ssicmds[i].type;
			break;
		}
	}

	switch(ssicmd) {
	case SSI_ECHO: {
		/* echo */
		int var = 0;
		/* int enc = 0; */
		const char *var_val = NULL;

		struct {
			const char *var;
			enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
					SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
		} echovars[] = {
			{ "DATE_GMT",      SSI_ECHO_DATE_GMT },
			{ "DATE_LOCAL",    SSI_ECHO_DATE_LOCAL },
			{ "DOCUMENT_NAME", SSI_ECHO_DOCUMENT_NAME },
			{ "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
			{ "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
			{ "USER_NAME",     SSI_ECHO_USER_NAME },

			{ NULL, SSI_ECHO_UNSET }
		};

/*
		struct {
			const char *var;
			enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
		} encvars[] = {
			{ "url",          SSI_ENC_URL },
			{ "none",         SSI_ENC_NONE },
			{ "entity",       SSI_ENC_ENTITY },

			{ NULL, SSI_ENC_UNSET }
		};
*/

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "var")) {
				int j;

				var_val = l[i+1];

				for (j = 0; echovars[j].var; j++) {
					if (0 == strcmp(l[i+1], echovars[j].var)) {
						var = echovars[j].type;
						break;
					}
				}
			} else if (0 == strcmp(l[i], "encoding")) {
/*
				int j;

				for (j = 0; encvars[j].var; j++) {
					if (0 == strcmp(l[i+1], encvars[j].var)) {
						enc = encvars[j].type;
						break;
					}
				}
*/
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (p->if_is_false) break;

		if (!var_val) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "var is missing");
			break;
		}

		switch(var) {
		case SSI_ECHO_USER_NAME: {
			struct passwd *pw;

			b = chunkqueue_get_append_buffer(con->write_queue);
#ifdef HAVE_PWD_H
			if (NULL == (pw = getpwuid(sce->st.st_uid))) {
				buffer_copy_long(b, sce->st.st_uid);
			} else {
				buffer_copy_string(b, pw->pw_name);
			}
#else
			buffer_copy_long(b, sce->st.st_uid);
#endif
			break;
		}
		case SSI_ECHO_LAST_MODIFIED:	{
			time_t t = sce->st.st_mtime;

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			} else {
				buffer_copy_string(b, buf);
			}
			break;
		}
		case SSI_ECHO_DATE_LOCAL: {
			time_t t = time(NULL);

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			} else {
				buffer_copy_string(b, buf);
			}
			break;
		}
		case SSI_ECHO_DATE_GMT: {
			time_t t = time(NULL);

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			} else {
				buffer_copy_string(b, buf);
			}
			break;
		}
		case SSI_ECHO_DOCUMENT_NAME: {
			char *sl;

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
				buffer_copy_string_buffer(b, con->physical.path);
			} else {
				buffer_copy_string(b, sl + 1);
			}
			break;
		}
		case SSI_ECHO_DOCUMENT_URI: {
			b = chunkqueue_get_append_buffer(con->write_queue);
			buffer_copy_string_buffer(b, con->uri.path);
			break;
		}
		default: {
			data_string *ds;
			/* check if it is a cgi-var */

			b = chunkqueue_get_append_buffer(con->write_queue);

			if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
				buffer_copy_string_buffer(b, ds->value);
			} else {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			}

			break;
		}
		}
		break;
	}
	case SSI_INCLUDE:
	case SSI_FLASTMOD:
	case SSI_FSIZE: {
		const char * file_path = NULL, *virt_path = NULL;
		struct stat st;
		char *sl;

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "file")) {
				file_path = l[i+1];
			} else if (0 == strcmp(l[i], "virtual")) {
				virt_path = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (!file_path && !virt_path) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "file or virtual are missing");
			break;
		}

		if (file_path && virt_path) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "only one of file and virtual is allowed here");
			break;
		}


		if (p->if_is_false) break;

		if (file_path) {
			/* current doc-root */
			if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
				buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
			} else {
				buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
			}

			buffer_copy_string(srv->tmp_buf, file_path);
			buffer_urldecode_path(srv->tmp_buf);
			buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
			buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
		} else {
			/* virtual */

			if (virt_path[0] == '/') {
				buffer_copy_string(p->stat_fn, virt_path);
			} else {
				/* there is always a / */
				sl = strrchr(con->uri.path->ptr, '/');

				buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
				buffer_append_string(p->stat_fn, virt_path);
			}

			buffer_urldecode_path(p->stat_fn);
			buffer_path_simplify(srv->tmp_buf, p->stat_fn);

			/* we have an uri */

			buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
			buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
		}

		if (0 == stat(p->stat_fn->ptr, &st)) {
			time_t t = st.st_mtime;

			switch (ssicmd) {
			case SSI_FSIZE:
				b = chunkqueue_get_append_buffer(con->write_queue);
				if (p->sizefmt) {
					int j = 0;
					const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };

					off_t s = st.st_size;

					for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);

					buffer_copy_off_t(b, s);
					buffer_append_string(b, abr[j]);
				} else {
					buffer_copy_off_t(b, st.st_size);
				}
				break;
			case SSI_FLASTMOD:
				b = chunkqueue_get_append_buffer(con->write_queue);
				if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
					buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
				} else {
					buffer_copy_string(b, buf);
				}
				break;
			case SSI_INCLUDE:
				chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);

				/* Keep the newest mtime of included files */
				if (st.st_mtime > include_file_last_mtime)
				  include_file_last_mtime = st.st_mtime;

				break;
			}
		} else {
			log_error_write(srv, __FILE__, __LINE__, "sbs",
					"ssi: stating failed ",
					p->stat_fn, strerror(errno));
		}
		break;
	}
	case SSI_SET: {
		const char *key = NULL, *val = NULL;
		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "var")) {
				key = l[i+1];
			} else if (0 == strcmp(l[i], "value")) {
				val = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (p->if_is_false) break;

		if (key && val) {
			data_string *ds;

			if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
				ds = data_string_init();
			}
			buffer_copy_string(ds->key,   key);
			buffer_copy_string(ds->value, val);

			array_insert_unique(p->ssi_vars, (data_unset *)ds);
		} else {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: var and value have to be set in",
					l[0], l[1]);
		}
		break;
	}
	case SSI_CONFIG:
		if (p->if_is_false) break;

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "timefmt")) {
				buffer_copy_string(p->timefmt, l[i+1]);
			} else if (0 == strcmp(l[i], "sizefmt")) {
				if (0 == strcmp(l[i+1], "abbrev")) {
					p->sizefmt = 1;
				} else if (0 == strcmp(l[i+1], "abbrev")) {
					p->sizefmt = 0;
				} else {
					log_error_write(srv, __FILE__, __LINE__, "sssss",
							"ssi: unknow value for attribute '",
							l[i],
							"' for ",
							l[1], l[i+1]);
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}
		break;
	case SSI_PRINTENV:
		if (p->if_is_false) break;

		b = chunkqueue_get_append_buffer(con->write_queue);
		for (i = 0; i < p->ssi_vars->used; i++) {
			data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];

			buffer_append_string_buffer(b, ds->key);
			buffer_append_string_len(b, CONST_STR_LEN("="));
			buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
			buffer_append_string_len(b, CONST_STR_LEN("\n"));
		}
		for (i = 0; i < p->ssi_cgi_env->used; i++) {
			data_string *ds = (data_string *)p->ssi_cgi_env->data[p->ssi_cgi_env->sorted[i]];

			buffer_append_string_buffer(b, ds->key);
			buffer_append_string_len(b, CONST_STR_LEN("="));
			buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
			buffer_append_string_len(b, CONST_STR_LEN("\n"));
		}

		break;
	case SSI_EXEC: {
		const char *cmd = NULL;
		pid_t pid;
		int from_exec_fds[2];

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "cmd")) {
				cmd = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (p->if_is_false) break;

		/* create a return pipe and send output to the html-page
		 *
		 * as exec is assumed evil it is implemented synchronously
		 */

		if (!cmd) break;
#ifdef HAVE_FORK
		if (pipe(from_exec_fds)) {
			log_error_write(srv, __FILE__, __LINE__, "ss",
					"pipe failed: ", strerror(errno));
			return -1;
		}

		/* fork, execve */
		switch (pid = fork()) {
		case 0: {
			/* move stdout to from_rrdtool_fd[1] */
			close(STDOUT_FILENO);
			dup2(from_exec_fds[1], STDOUT_FILENO);
			close(from_exec_fds[1]);
			/* not needed */
			close(from_exec_fds[0]);

			/* close stdin */
			close(STDIN_FILENO);

			execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);

			log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);

			/* */
			SEGFAULT();
			break;
		}
		case -1:
			/* error */
			log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
			break;
		default: {
			/* father */
			int status;
			ssize_t r;
			int was_interrupted = 0;

			close(from_exec_fds[1]);

			/* wait for the client to end */

			/*
			 * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
			 */
			do {
				if (-1 == waitpid(pid, &status, 0)) {
					if (errno == EINTR) {
						was_interrupted++;
					} else {
						was_interrupted = 0;
						log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
					}
				} else if (WIFEXITED(status)) {
					int toread;
					/* read everything from client and paste it into the output */
					was_interrupted = 0;
	
					while(1) {
						if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
							log_error_write(srv, __FILE__, __LINE__, "s",
								"unexpected end-of-file (perhaps the ssi-exec process died)");
							return -1;
						}
	
						if (toread > 0) {
							b = chunkqueue_get_append_buffer(con->write_queue);
	
							buffer_prepare_copy(b, toread + 1);
	
							if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
								/* read failed */
								break;
							} else {
								b->used = r;
								b->ptr[b->used++] = '\0';
							}
						} else {
							break;
						}
					}
				} else {
					was_interrupted = 0;
					log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
				}
			} while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */

			close(from_exec_fds[0]);

			break;
		}
		}
#else

		return -1;
#endif

		break;
	}
	case SSI_IF: {
		const char *expr = NULL;

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "expr")) {
				expr = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (!expr) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "expr missing");
			break;
		}

		if ((!p->if_is_false) &&
		    ((p->if_is_false_level == 0) ||
		     (p->if_level < p->if_is_false_level))) {
			switch (ssi_eval_expr(srv, con, p, expr)) {
			case -1:
			case 0:
				p->if_is_false = 1;
				p->if_is_false_level = p->if_level;
				break;
			case 1:
				p->if_is_false = 0;
				break;
			}
		}

		p->if_level++;

		break;
	}
	case SSI_ELSE:
		p->if_level--;

		if (p->if_is_false) {
			if ((p->if_level == p->if_is_false_level) &&
			    (p->if_is_false_endif == 0)) {
				p->if_is_false = 0;
			}
		} else {
			p->if_is_false = 1;

			p->if_is_false_level = p->if_level;
		}
		p->if_level++;

		break;
	case SSI_ELIF: {
		const char *expr = NULL;
		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "expr")) {
				expr = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (!expr) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "expr missing");
			break;
		}

		p->if_level--;

		if (p->if_level == p->if_is_false_level) {
			if ((p->if_is_false) &&
			    (p->if_is_false_endif == 0)) {
				switch (ssi_eval_expr(srv, con, p, expr)) {
				case -1:
				case 0:
					p->if_is_false = 1;
					p->if_is_false_level = p->if_level;
					break;
				case 1:
					p->if_is_false = 0;
					break;
				}
			} else {
				p->if_is_false = 1;
				p->if_is_false_level = p->if_level;
				p->if_is_false_endif = 1;
			}
		}

		p->if_level++;

		break;
	}
	case SSI_ENDIF:
		p->if_level--;

		if (p->if_level == p->if_is_false_level) {
			p->if_is_false = 0;
			p->if_is_false_endif = 0;
		}

		break;
	default:
		log_error_write(srv, __FILE__, __LINE__, "ss",
				"ssi: unknow ssi-command:",
				l[1]);
		break;
	}

	return 0;

}
Esempio n. 25
0
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
*/
static void yy_reduce(
  yyParser *yypParser,         /* The parser */
  int yyruleno                 /* Number of the rule by which to reduce */
){
  int yygoto;                     /* The next state */
  int yyact;                      /* The next action */
  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
  yyStackEntry *yymsp;            /* The top of the parser's stack */
  int yysize;                     /* Amount to pop the stack */
  configparserARG_FETCH;
  yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
  if( yyTraceFILE && yyruleno>=0
        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
      yyRuleName[yyruleno]);
  }
#endif /* NDEBUG */

  switch( yyruleno ){
  /* Beginning here are the reduction cases.  A typical example
  ** follows:
  **   case 0:
  **  #line <lineno> <grammarfile>
  **     { ... }           // User supplied code
  **  #line <lineno> <thisfile>
  **     break;
  */
      case 0:
        /* No destructor defined for metalines */
        break;
      case 1:
        /* No destructor defined for metalines */
        /* No destructor defined for metaline */
        break;
      case 2:
        break;
      case 3:
        /* No destructor defined for varline */
        break;
      case 4:
        /* No destructor defined for global */
        break;
      case 5:
#line 115 "./configparser.y"
{ yymsp[-1].minor.yy78 = NULL; }
#line 822 "configparser.c"
  yy_destructor(1,&yymsp[0].minor);
        break;
      case 6:
        /* No destructor defined for include */
        break;
      case 7:
        /* No destructor defined for include_shell */
        break;
      case 8:
  yy_destructor(1,&yymsp[0].minor);
        break;
      case 9:
#line 144 "./configparser.y"
{
  if (ctx->ok) {
    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
    if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
      fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
          ctx->current->context_ndx,
          ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
      ctx->ok = 0;
    } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
      yymsp[0].minor.yy41 = NULL;
    } else {
      fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
              ctx->current->context_ndx,
              ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr);
      ctx->ok = 0;
      yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
      yymsp[0].minor.yy41 = NULL;
    }
  }
  buffer_free(yymsp[-2].minor.yy43);
  yymsp[-2].minor.yy43 = NULL;
}
#line 859 "configparser.c"
  yy_destructor(2,&yymsp[-1].minor);
        break;
      case 10:
#line 168 "./configparser.y"
{
  array *vars = ctx->current->value;
  data_unset *du;

  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
        ctx->current->context_ndx,
        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
    ctx->ok = 0;
  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
    /* exists in current block */
    du = configparser_merge_data(du, yymsp[0].minor.yy41);
    if (NULL == du) {
      ctx->ok = 0;
    }
    else {
      buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
      array_replace(vars, du);
    }
    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
    du = configparser_merge_data(du, yymsp[0].minor.yy41);
    if (NULL == du) {
      ctx->ok = 0;
      du->free(du);
    }
    else {
      buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
      array_insert_unique(ctx->current->value, du);
    }
    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  } else {
    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
  }
  buffer_free(yymsp[-2].minor.yy43);
  yymsp[-2].minor.yy43 = NULL;
  yymsp[0].minor.yy41 = NULL;
}
#line 903 "configparser.c"
  yy_destructor(3,&yymsp[-1].minor);
        break;
      case 11:
#line 208 "./configparser.y"
{
  if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
    yygotominor.yy43 = buffer_init_string("var.");
    buffer_append_string_buffer(yygotominor.yy43, yymsp[0].minor.yy0);
    buffer_free(yymsp[0].minor.yy0);
    yymsp[0].minor.yy0 = NULL;
  } else {
    yygotominor.yy43 = yymsp[0].minor.yy0;
    yymsp[0].minor.yy0 = NULL;
  }
}
#line 919 "configparser.c"
        break;
      case 12:
#line 220 "./configparser.y"
{
  yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
  if (NULL == yygotominor.yy41) {
    ctx->ok = 0;
  }
  yymsp[-2].minor.yy41 = NULL;
  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 932 "configparser.c"
  yy_destructor(5,&yymsp[-1].minor);
        break;
      case 13:
#line 230 "./configparser.y"
{
  yygotominor.yy41 = yymsp[0].minor.yy41;
  yymsp[0].minor.yy41 = NULL;
}
#line 941 "configparser.c"
        break;
      case 14:
#line 235 "./configparser.y"
{
  yygotominor.yy41 = NULL;
  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
    char *env;

    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
      data_string *ds;
      ds = data_string_init();
      buffer_append_string(ds->value, env);
      yygotominor.yy41 = (data_unset *)ds;
    }
    else {
      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
      ctx->ok = 0;
    }
  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
    ctx->ok = 0;
  }
  if (!yygotominor.yy41) {
    /* make a dummy so it won't crash */
    yygotominor.yy41 = (data_unset *)data_string_init();
  }
  buffer_free(yymsp[0].minor.yy43);
  yymsp[0].minor.yy43 = NULL;
}
#line 971 "configparser.c"
        break;
      case 15:
#line 262 "./configparser.y"
{
  yygotominor.yy41 = (data_unset *)data_string_init();
  buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
  buffer_free(yymsp[0].minor.yy0);
  yymsp[0].minor.yy0 = NULL;
}
#line 981 "configparser.c"
        break;
      case 16:
#line 269 "./configparser.y"
{
  yygotominor.yy41 = (data_unset *)data_integer_init();
  ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
  buffer_free(yymsp[0].minor.yy0);
  yymsp[0].minor.yy0 = NULL;
}
#line 991 "configparser.c"
        break;
      case 17:
#line 275 "./configparser.y"
{
  yygotominor.yy41 = (data_unset *)data_array_init();
  array_free(((data_array *)(yygotominor.yy41))->value);
  ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
  yymsp[0].minor.yy40 = NULL;
}
#line 1001 "configparser.c"
        break;
      case 18:
#line 281 "./configparser.y"
{
  yygotominor.yy40 = array_init();
}
#line 1008 "configparser.c"
  yy_destructor(8,&yymsp[-1].minor);
  yy_destructor(9,&yymsp[0].minor);
        break;
      case 19:
#line 284 "./configparser.y"
{
  yygotominor.yy40 = yymsp[-1].minor.yy40;
  yymsp[-1].minor.yy40 = NULL;
}
#line 1018 "configparser.c"
  yy_destructor(8,&yymsp[-2].minor);
  yy_destructor(9,&yymsp[0].minor);
        break;
      case 20:
#line 289 "./configparser.y"
{
  if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
      NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
    array_insert_unique(yymsp[-2].minor.yy40, yymsp[0].minor.yy41);
    yymsp[0].minor.yy41 = NULL;
  } else {
    fprintf(stderr, "Duplicate array-key: %s\n",
            yymsp[0].minor.yy41->key->ptr);
    ctx->ok = 0;
    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
    yymsp[0].minor.yy41 = NULL;
  }

  yygotominor.yy40 = yymsp[-2].minor.yy40;
  yymsp[-2].minor.yy40 = NULL;
}
#line 1040 "configparser.c"
  yy_destructor(10,&yymsp[-1].minor);
        break;
      case 21:
#line 306 "./configparser.y"
{
  yygotominor.yy40 = yymsp[-1].minor.yy40;
  yymsp[-1].minor.yy40 = NULL;
}
#line 1049 "configparser.c"
  yy_destructor(10,&yymsp[0].minor);
        break;
      case 22:
#line 311 "./configparser.y"
{
  yygotominor.yy40 = array_init();
  array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 1059 "configparser.c"
        break;
      case 23:
#line 317 "./configparser.y"
{
  yygotominor.yy41 = yymsp[0].minor.yy41;
  yymsp[0].minor.yy41 = NULL;
}
#line 1067 "configparser.c"
        break;
      case 24:
#line 321 "./configparser.y"
{
  buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
  buffer_free(yymsp[-2].minor.yy43);
  yymsp[-2].minor.yy43 = NULL;

  yygotominor.yy41 = yymsp[0].minor.yy41;
  yymsp[0].minor.yy41 = NULL;
}
#line 1079 "configparser.c"
  yy_destructor(11,&yymsp[-1].minor);
        break;
      case 25:
  yy_destructor(1,&yymsp[0].minor);
        break;
      case 26:
        break;
      case 27:
#line 333 "./configparser.y"
{
  data_config *dc;
  dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
  assert(dc);
  configparser_push(ctx, dc, 0);
}
#line 1095 "configparser.c"
  yy_destructor(12,&yymsp[0].minor);
        break;
      case 28:
#line 340 "./configparser.y"
{
  data_config *cur;

  cur = ctx->current;
  configparser_pop(ctx);

  assert(cur && ctx->current);

  yygotominor.yy78 = cur;
}
#line 1110 "configparser.c"
        /* No destructor defined for globalstart */
  yy_destructor(13,&yymsp[-2].minor);
        /* No destructor defined for metalines */
  yy_destructor(14,&yymsp[0].minor);
        break;
      case 29:
#line 351 "./configparser.y"
{
  assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
  yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
  yymsp[-3].minor.yy78->next = yymsp[0].minor.yy78;
  yygotominor.yy78 = yymsp[0].minor.yy78;
  yymsp[-3].minor.yy78 = NULL;
  yymsp[0].minor.yy78 = NULL;
}
#line 1126 "configparser.c"
        /* No destructor defined for eols */
  yy_destructor(15,&yymsp[-1].minor);
        break;
      case 30:
#line 360 "./configparser.y"
{
  yygotominor.yy78 = yymsp[0].minor.yy78;
  yymsp[0].minor.yy78 = NULL;
}
#line 1136 "configparser.c"
        break;
      case 31:
#line 365 "./configparser.y"
{
  data_config *cur;

  cur = ctx->current;
  configparser_pop(ctx);

  assert(cur && ctx->current);

  yygotominor.yy78 = cur;
}
#line 1150 "configparser.c"
        /* No destructor defined for context */
  yy_destructor(13,&yymsp[-2].minor);
        /* No destructor defined for metalines */
  yy_destructor(14,&yymsp[0].minor);
        break;
      case 32:
#line 376 "./configparser.y"
{
  data_config *dc;
  buffer *b, *rvalue, *op;

  if (ctx->ok && yymsp[0].minor.yy41->type != TYPE_STRING) {
    fprintf(stderr, "rvalue must be string");
    ctx->ok = 0;
  }

  switch(yymsp[-1].minor.yy27) {
  case CONFIG_COND_NE:
    op = buffer_init_string("!=");
    break;
  case CONFIG_COND_EQ:
    op = buffer_init_string("==");
    break;
  case CONFIG_COND_NOMATCH:
    op = buffer_init_string("!~");
    break;
  case CONFIG_COND_MATCH:
    op = buffer_init_string("=~");
    break;
  default:
    assert(0);
    return;
  }

  b = buffer_init();
  buffer_copy_string_buffer(b, ctx->current->key);
  buffer_append_string(b, "/");
  buffer_append_string_buffer(b, yymsp[-5].minor.yy0);
  buffer_append_string_buffer(b, yymsp[-3].minor.yy43);
  buffer_append_string_buffer(b, op);
  rvalue = ((data_string*)yymsp[0].minor.yy41)->value;
  buffer_append_string_buffer(b, rvalue);

  if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
    configparser_push(ctx, dc, 0);
  } else {
    struct {
      comp_key_t comp;
      char *comp_key;
      size_t len;
    } comps[] = {
      { COMP_SERVER_SOCKET,      CONST_STR_LEN("SERVER[\"socket\"]"   ) },
      { COMP_HTTP_URL,           CONST_STR_LEN("HTTP[\"url\"]"        ) },
      { COMP_HTTP_HOST,          CONST_STR_LEN("HTTP[\"host\"]"       ) },
      { COMP_HTTP_REFERER,       CONST_STR_LEN("HTTP[\"referer\"]"    ) },
      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"useragent\"]"  ) },
      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"user-agent\"]"  ) },
      { COMP_HTTP_COOKIE,        CONST_STR_LEN("HTTP[\"cookie\"]"     ) },
      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remoteip\"]"   ) },
      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remote-ip\"]"   ) },
      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"querystring\"]") },
      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"query-string\"]") },
      { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
      { COMP_HTTP_SCHEME,        CONST_STR_LEN("HTTP[\"scheme\"]"     ) },
      { COMP_UNSET, NULL, 0 },
    };
    size_t i;

    dc = data_config_init();

    buffer_copy_string_buffer(dc->key, b);
    buffer_copy_string_buffer(dc->op, op);
    buffer_copy_string_buffer(dc->comp_key, yymsp[-5].minor.yy0);
    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
    buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy43);
    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
    dc->cond = yymsp[-1].minor.yy27;

    for (i = 0; comps[i].comp_key; i ++) {
      if (buffer_is_equal_string(
            dc->comp_key, comps[i].comp_key, comps[i].len)) {
        dc->comp = comps[i].comp;
        break;
      }
    }
    if (COMP_UNSET == dc->comp) {
      fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
      ctx->ok = 0;
    }

    switch(yymsp[-1].minor.yy27) {
    case CONFIG_COND_NE:
    case CONFIG_COND_EQ:
      dc->string = buffer_init_buffer(rvalue);
      break;
    case CONFIG_COND_NOMATCH:
    case CONFIG_COND_MATCH: {
#ifdef HAVE_PCRE_H
      const char *errptr;
      int erroff;

      if (NULL == (dc->regex =
          pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
        dc->string = buffer_init_string(errptr);
        dc->cond = CONFIG_COND_UNSET;

        fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
            rvalue->ptr, errptr, erroff);

        ctx->ok = 0;
      } else if (NULL == (dc->regex_study =
          pcre_study(dc->regex, 0, &errptr)) &&
                 errptr != NULL) {
        fprintf(stderr, "studying regex failed: %s -> %s\n",
            rvalue->ptr, errptr);
        ctx->ok = 0;
      } else {
        dc->string = buffer_init_buffer(rvalue);
      }
#else
      fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
		      "(perhaps just a missing pcre-devel package ?) \n",
                      yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr);
      ctx->ok = 0;
#endif
      break;
    }

    default:
      fprintf(stderr, "unknown condition for $%s[%s]\n",
                      yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr);
      ctx->ok = 0;
      break;
    }

    configparser_push(ctx, dc, 1);
  }

  buffer_free(b);
  buffer_free(op);
  buffer_free(yymsp[-5].minor.yy0);
  yymsp[-5].minor.yy0 = NULL;
  buffer_free(yymsp[-3].minor.yy43);
  yymsp[-3].minor.yy43 = NULL;
  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 1298 "configparser.c"
  yy_destructor(16,&yymsp[-6].minor);
  yy_destructor(18,&yymsp[-4].minor);
  yy_destructor(19,&yymsp[-2].minor);
        break;
      case 33:
#line 516 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_EQ;
}
#line 1308 "configparser.c"
  yy_destructor(20,&yymsp[0].minor);
        break;
      case 34:
#line 519 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_MATCH;
}
#line 1316 "configparser.c"
  yy_destructor(21,&yymsp[0].minor);
        break;
      case 35:
#line 522 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_NE;
}
#line 1324 "configparser.c"
  yy_destructor(22,&yymsp[0].minor);
        break;
      case 36:
#line 525 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_NOMATCH;
}
#line 1332 "configparser.c"
  yy_destructor(23,&yymsp[0].minor);
        break;
      case 37:
#line 529 "./configparser.y"
{
  yygotominor.yy43 = NULL;
  if (ctx->ok) {
    if (yymsp[0].minor.yy41->type == TYPE_STRING) {
      yygotominor.yy43 = buffer_init_buffer(((data_string*)yymsp[0].minor.yy41)->value);
    } else if (yymsp[0].minor.yy41->type == TYPE_INTEGER) {
      yygotominor.yy43 = buffer_init();
      buffer_copy_long(yygotominor.yy43, ((data_integer *)yymsp[0].minor.yy41)->value);
    } else {
      fprintf(stderr, "operand must be string");
      ctx->ok = 0;
    }
  }
  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 1353 "configparser.c"
        break;
      case 38:
#line 546 "./configparser.y"
{
  if (ctx->ok) {
    if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
      ctx->ok = 0;
    }
    buffer_free(yymsp[0].minor.yy43);
    yymsp[0].minor.yy43 = NULL;
  }
}
#line 1366 "configparser.c"
  yy_destructor(24,&yymsp[-1].minor);
        break;
      case 39:
#line 556 "./configparser.y"
{
  if (ctx->ok) {
    if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
      ctx->ok = 0;
    }
    buffer_free(yymsp[0].minor.yy43);
    yymsp[0].minor.yy43 = NULL;
  }
}
#line 1380 "configparser.c"
  yy_destructor(25,&yymsp[-1].minor);
        break;
  };
  yygoto = yyRuleInfo[yyruleno].lhs;
  yysize = yyRuleInfo[yyruleno].nrhs;
  yypParser->yyidx -= yysize;
  yyact = yy_find_reduce_action(yypParser,yygoto);
  if( yyact < YYNSTATE ){
    yy_shift(yypParser,yyact,yygoto,&yygotominor);
  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
    yy_accept(yypParser);
  }
}
Esempio n. 26
0
static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
	char *s, *ns;
	int http_response_status = -1;

	UNUSED(srv);

	/* \r\n -> \0\0 */

	buffer_copy_string_buffer(p->parse_response, in);

	for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
		char *key, *value;
		int key_len;
		data_string *ds;
		int copy_header;

		ns[0] = '\0';
		ns[1] = '\0';

		if (-1 == http_response_status) {
			/* The first line of a Response message is the Status-Line */

			for (key=s; *key && *key != ' '; key++);

			if (*key) {
				http_response_status = (int) strtol(key, NULL, 10);
				if (http_response_status <= 0) http_response_status = 502;
			} else {
				http_response_status = 502;
			}

			con->http_status = http_response_status;
			con->parsed_response |= HTTP_STATUS;
			continue;
		}

		if (NULL == (value = strchr(s, ':'))) {
			/* now we expect: "<key>: <value>\n" */

			continue;
		}

		key = s;
		key_len = value - key;

		value++;
		/* strip WS */
		while (*value == ' ' || *value == '\t') value++;

		copy_header = 1;

		switch(key_len) {
		case 4:
			if (0 == strncasecmp(key, "Date", key_len)) {
				con->parsed_response |= HTTP_DATE;
			}
			break;
		case 8:
			if (0 == strncasecmp(key, "Location", key_len)) {
				con->parsed_response |= HTTP_LOCATION;
			}
			break;
		case 10:
			if (0 == strncasecmp(key, "Connection", key_len)) {
				copy_header = 0;
			}
			break;
		case 14:
			if (0 == strncasecmp(key, "Content-Length", key_len)) {
				con->response.content_length = strtol(value, NULL, 10);
				con->parsed_response |= HTTP_CONTENT_LENGTH;
			}
			break;
		default:
			break;
		}

		if (copy_header) {
			if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
				ds = data_response_init();
			}
			buffer_copy_string_len(ds->key, key, key_len);
			buffer_copy_string(ds->value, value);

			array_insert_unique(con->response.headers, (data_unset *)ds);
		}
	}

	return 0;
}
Esempio n. 27
0
static int request_check_hostname(server * srv, connection * con, buffer * host)
{
	enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
	size_t i;
	int label_len = 0;
	size_t host_len;
	char *colon;
	int is_ip = -1;				/* -1 don't know yet, 0 no, 1 yes */
	int level = 0;

	UNUSED(srv);
	UNUSED(con);

	/*
	 *       hostport      = host [ ":" port ]
	 *       host          = hostname | IPv4address | IPv6address
	 *       hostname      = *( domainlabel "." ) toplabel [ "." ]
	 *       domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
	 *       toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
	 *       IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
	 *       IPv6address   = "[" ... "]" //IPv6地址用[]包围.
	 *       port          = *digit
	 */

	/*
	 * no Host: 
	 */
	if (!host || host->used == 0)
		return 0;

	host_len = host->used - 1;

	/*
	 * IPv6 adress 
	 */
	if (host->ptr[0] == '[')
	{
		char *c = host->ptr + 1;
		int colon_cnt = 0;

		/*
		 * check portnumber 
		 */
		for (; *c && *c != ']'; c++)
		{
			if (*c == ':')
			{
				//至多7个分号。
				if (++colon_cnt > 7)
				{
					return -1;
				}
			} 
			else if (!light_isxdigit(*c))
			{
				return -1;
			}
		}

		/*
		 * missing ] 
		 */
		if (!*c)
		{
			return -1;
		}

		/*
		 * check port 
		 */
		if (*(c + 1) == ':')
		{
			for (c += 2; *c; c++)
			{
				if (!light_isdigit(*c))
				{
					return -1;
				}
			}
		}
		return 0;
	}

	if (NULL != (colon = memchr(host->ptr, ':', host_len)))
	{
		char *c = colon + 1;

		/*
		 * check portnumber 
		 */
		for (; *c; c++)
		{
			if (!light_isdigit(*c))
				return -1;
		}

		/*
		 * remove the port from the host-len 
		 */
		host_len = colon - host->ptr;
	}

	/*
	 * Host is empty 
	 */
	if (host_len == 0)
		return -1;

	/*
	 * if the hostname ends in a "." strip it 
	 */
	if (host->ptr[host_len - 1] == '.')
		host_len -= 1;

	/*
	 * scan from the right and skip the \0 
	 */
	for (i = host_len - 1; i + 1 > 0; i--)
	{
		const char c = host->ptr[i];

		switch (stage)
		{
		case TOPLABEL:
			if (c == '.')
			{
				/*/**
 * header lines中的value,可以是以","分割的多个value。
 * 这个函数将v中value,按照","分割成多个值,存放在vals中。
 */
int http_request_split_value(array * vals, buffer * b)
{
	char *s;
	size_t i;
	int state = 0;
	/*
	 * parse
	 * val1, val2, val3, val4
	 * into a array (more or less a explode() incl. striping of whitespaces
	 */

	if (b->used == 0)
		return 0;
	s = b->ptr;
	for (i = 0; i < b->used - 1;)
	{
		char *start = NULL, *end = NULL;
		data_string *ds;

		switch (state)
		{
		case 0:				/* ws */

			/*
			 * skip ws 
			 */
			for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);

			state = 1;
			break;
		case 1:				/* value */
			start = s;

			for (; *s != ',' && i < b->used - 1; i++, s++);
			end = s - 1;
			//去掉空格
			for (; (*end == ' ' || *end == '\t') && end > start; end--);

			if (NULL ==	(ds = (data_string *) array_get_unused_element(vals, TYPE_STRING)))
			{
				ds = data_string_init();
			}

			buffer_copy_string_len(ds->value, start, end - start + 1);
			array_insert_unique(vals, (data_unset *) ds);

			if (*s == ',')
			{
				state = 0;
				i++;
				s++;
			} 
			else
			{
				/*
				 * end of string 
				 */
				state = 2;
			}
			break;
		default:
			i++;
			break;
		}
	}
	return 0;
}
				 * only switch stage, if this is not the last character 
				 */
				if (i != host_len - 1)
				{
					if (label_len == 0)
					{
						return -1;
					}

					/*
					 * check the first character at right of the dot 
					 */
					if (is_ip == 0)
					{
						if (!light_isalpha(host->ptr[i + 1]))
						{
							return -1;
						}
					} 
					else if (!light_isdigit(host->ptr[i + 1]))
					{
						is_ip = 0;
					} 
					else if ('-' == host->ptr[i + 1])
					{
						return -1;
					} 
					else
					{
						/*
						 * just digits 
						 */
						is_ip = 1;
					}

					stage = DOMAINLABEL;

					label_len = 0;
					level++;
				} 
				else if (i == 0)
				{
					/*
					 * just a dot and nothing else is evil 
					 */
					return -1;
				}
			} 
			else if (i == 0)
Esempio n. 28
0
int config_read(server *srv, const char *fn) {
    config_t context;
    data_config *dc;
    data_integer *dpid;
    data_string *dcwd;
    int ret;
    char *pos;
    data_array *modules;

    context_init(srv, &context);
    context.all_configs = srv->config_context;

#ifdef __WIN32
    pos = strrchr(fn, '\\');
#else
    pos = strrchr(fn, '/');
#endif
    if (pos) {
        buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
        fn = pos + 1;
    }

    dc = data_config_init();
    buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));

    assert(context.all_configs->used == 0);
    dc->context_ndx = context.all_configs->used;
    array_insert_unique(context.all_configs, (data_unset *)dc);
    context.current = dc;

    /* default context */
    srv->config = dc->value;
    dpid = data_integer_init();
    dpid->value = getpid();
    buffer_copy_string_len(dpid->key, CONST_STR_LEN("var.PID"));
    array_insert_unique(srv->config, (data_unset *)dpid);

    dcwd = data_string_init();
    buffer_prepare_copy(dcwd->value, 1024);
    if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
        dcwd->value->used = strlen(dcwd->value->ptr) + 1;
        buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
        array_insert_unique(srv->config, (data_unset *)dcwd);
    }

    ret = config_parse_file(srv, &context, fn);

    /* remains nothing if parser is ok */
    assert(!(0 == ret && context.ok && 0 != context.configs_stack->used));
    context_free(&context);

    if (0 != ret) {
        return ret;
    }

    if (NULL != (dc = (data_config *)array_get_element(srv->config_context, "global"))) {
        srv->config = dc->value;
    } else {
        return -1;
    }

    if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
        data_string *ds;
        data_array *prepends;

        if (modules->type != TYPE_ARRAY) {
            fprintf(stderr, "server.modules must be an array");
            return -1;
        }

        prepends = data_array_init();

        /* prepend default modules */
        if (NULL == array_get_element(modules->value, "mod_indexfile")) {
            ds = data_string_init();
            buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
            array_insert_unique(prepends->value, (data_unset *)ds);
        }

        prepends = (data_array *)configparser_merge_data((data_unset *)prepends, (data_unset *)modules);
        buffer_copy_string_buffer(prepends->key, modules->key);
        array_replace(srv->config, (data_unset *)prepends);
        modules->free((data_unset *)modules);
        modules = prepends;

        /* append default modules */
        if (NULL == array_get_element(modules->value, "mod_dirlisting")) {
            ds = data_string_init();
            buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
            array_insert_unique(modules->value, (data_unset *)ds);
        }

        if (NULL == array_get_element(modules->value, "mod_staticfile")) {
            ds = data_string_init();
            buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
            array_insert_unique(modules->value, (data_unset *)ds);
        }
    } else {
        data_string *ds;

        modules = data_array_init();

        /* server.modules is not set */
        ds = data_string_init();
        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
        array_insert_unique(modules->value, (data_unset *)ds);

        ds = data_string_init();
        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
        array_insert_unique(modules->value, (data_unset *)ds);

        ds = data_string_init();
        buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
        array_insert_unique(modules->value, (data_unset *)ds);

        buffer_copy_string_len(modules->key, CONST_STR_LEN("server.modules"));
        array_insert_unique(srv->config, (data_unset *)modules);
    }


    if (0 != config_insert(srv)) {
        return -1;
    }

    return 0;
}
Esempio n. 29
0
int connection_state_machine(server *srv, connection *con) {
	int done = 0, r;

	if (srv->srvconf.log_state_handling) {
		log_error_write(srv, __FILE__, __LINE__, "sds",
				"state at start",
				con->fd,
				connection_get_state(con->state));
	}

	while (done == 0) {
		size_t ostate = con->state;

		if (srv->srvconf.log_state_handling) {
			log_error_write(srv, __FILE__, __LINE__, "sds",
					"state for fd", con->fd, connection_get_state(con->state));
		}

		switch (con->state) {
		case CON_STATE_REQUEST_START: /* transient */
			con->request_start = srv->cur_ts;
			con->read_idle_ts = srv->cur_ts;
			if (con->conf.high_precision_timestamps)
				log_clock_gettime_realtime(&con->request_start_hp);

			con->request_count++;
			con->loops_per_request = 0;

			connection_set_state(srv, con, CON_STATE_READ);

			break;
		case CON_STATE_REQUEST_END: /* transient */
			buffer_reset(con->uri.authority);
			buffer_reset(con->uri.path);
			buffer_reset(con->uri.query);
			buffer_reset(con->request.orig_uri);

			if (http_request_parse(srv, con)) {
				/* we have to read some data from the POST request */

				connection_set_state(srv, con, CON_STATE_READ_POST);

				break;
			}

			connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);

			break;
		case CON_STATE_READ_POST:
		case CON_STATE_HANDLE_REQUEST:
			/*
			 * the request is parsed
			 *
			 * decided what to do with the request
			 * -
			 *
			 *
			 */

			switch (r = http_response_prepare(srv, con)) {
			case HANDLER_WAIT_FOR_EVENT:
				if (!con->file_finished && (!con->file_started || 0 == con->conf.stream_response_body)) {
					break; /* come back here */
				}
				/* response headers received from backend; fall through to start response */
			case HANDLER_FINISHED:
				if (con->error_handler_saved_status > 0) {
					con->request.http_method = con->error_handler_saved_method;
				}
				if (con->mode == DIRECT) {
					if (con->error_handler_saved_status) {
						if (con->error_handler_saved_status > 0) {
							con->http_status = con->error_handler_saved_status;
						} else if (con->http_status == 404 || con->http_status == 403) {
							/* error-handler-404 is a 404 */
							con->http_status = -con->error_handler_saved_status;
						} else {
							/* error-handler-404 is back and has generated content */
							/* if Status: was set, take it otherwise use 200 */
						}
					} else if (con->http_status >= 400) {
						buffer *error_handler = NULL;
						if (!buffer_string_is_empty(con->conf.error_handler)) {
							error_handler = con->conf.error_handler;
						} else if ((con->http_status == 404 || con->http_status == 403)
							   && !buffer_string_is_empty(con->conf.error_handler_404)) {
							error_handler = con->conf.error_handler_404;
						}

						if (error_handler) {
							/* call error-handler */

							/* set REDIRECT_STATUS to save current HTTP status code
							 * for access by dynamic handlers
							 * https://redmine.lighttpd.net/issues/1828 */
							data_string *ds;
							if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
								ds = data_string_init();
							}
							buffer_copy_string_len(ds->key, CONST_STR_LEN("REDIRECT_STATUS"));
							buffer_append_int(ds->value, con->http_status);
							array_insert_unique(con->environment, (data_unset *)ds);

							if (error_handler == con->conf.error_handler) {
								plugins_call_connection_reset(srv, con);

								if (con->request.content_length) {
									if (con->request.content_length != con->request_content_queue->bytes_in) {
										con->keep_alive = 0;
									}
									con->request.content_length = 0;
									chunkqueue_reset(con->request_content_queue);
								}

								con->is_writable = 1;
								con->file_finished = 0;
								con->file_started = 0;
								con->got_response = 0;
								con->parsed_response = 0;
								con->response.keep_alive = 0;
								con->response.content_length = -1;
								con->response.transfer_encoding = 0;

								con->error_handler_saved_status = con->http_status;
								con->error_handler_saved_method = con->request.http_method;

								con->request.http_method = HTTP_METHOD_GET;
							} else { /*(preserve behavior for server.error-handler-404)*/
								con->error_handler_saved_status = -con->http_status; /*(negative to flag old behavior)*/
							}

							buffer_copy_buffer(con->request.uri, error_handler);
							connection_handle_errdoc_init(srv, con);
							con->http_status = 0; /*(after connection_handle_errdoc_init())*/

							done = -1;
							break;
						}
					}
				}
				if (con->http_status == 0) con->http_status = 200;

				/* we have something to send, go on */
				connection_set_state(srv, con, CON_STATE_RESPONSE_START);
				break;
			case HANDLER_WAIT_FOR_FD:
				srv->want_fds++;

				fdwaitqueue_append(srv, con);

				break;
			case HANDLER_COMEBACK:
				done = -1;
				break;
			case HANDLER_ERROR:
				/* something went wrong */
				connection_set_state(srv, con, CON_STATE_ERROR);
				break;
			default:
				log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
				break;
			}

			if (con->state == CON_STATE_HANDLE_REQUEST && ostate == CON_STATE_READ_POST) {
				ostate = CON_STATE_HANDLE_REQUEST;
			}
			break;
		case CON_STATE_RESPONSE_START:
			/*
			 * the decision is done
			 * - create the HTTP-Response-Header
			 *
			 */

			if (-1 == connection_handle_write_prepare(srv, con)) {
				connection_set_state(srv, con, CON_STATE_ERROR);

				break;
			}

			connection_set_state(srv, con, CON_STATE_WRITE);
			break;
		case CON_STATE_RESPONSE_END: /* transient */
		case CON_STATE_ERROR:        /* transient */
			connection_handle_response_end_state(srv, con);
			break;
		case CON_STATE_CONNECT:
			chunkqueue_reset(con->read_queue);

			con->request_count = 0;

			break;
		case CON_STATE_CLOSE:
			connection_handle_close_state(srv, con);
			break;
		case CON_STATE_READ:
			connection_handle_read_state(srv, con);
			break;
		case CON_STATE_WRITE:
			do {
				/* only try to write if we have something in the queue */
				if (!chunkqueue_is_empty(con->write_queue)) {
					if (con->is_writable) {
						if (-1 == connection_handle_write(srv, con)) {
							log_error_write(srv, __FILE__, __LINE__, "ds",
									con->fd,
									"handle write failed.");
							connection_set_state(srv, con, CON_STATE_ERROR);
							break;
						}
						if (con->state != CON_STATE_WRITE) break;
					}
				} else if (con->file_finished) {
					connection_set_state(srv, con, CON_STATE_RESPONSE_END);
					break;
				}

				if (con->mode != DIRECT && !con->file_finished) {
					switch(r = plugins_call_handle_subrequest(srv, con)) {
					case HANDLER_WAIT_FOR_EVENT:
					case HANDLER_FINISHED:
					case HANDLER_GO_ON:
						break;
					case HANDLER_WAIT_FOR_FD:
						srv->want_fds++;
						fdwaitqueue_append(srv, con);
						break;
					case HANDLER_COMEBACK:
					default:
						log_error_write(srv, __FILE__, __LINE__, "sdd", "unexpected subrequest handler ret-value: ", con->fd, r);
						/* fall through */
					case HANDLER_ERROR:
						connection_set_state(srv, con, CON_STATE_ERROR);
						break;
					}
				}
			} while (con->state == CON_STATE_WRITE && (!chunkqueue_is_empty(con->write_queue) ? con->is_writable : con->file_finished));

			break;
		default:
			log_error_write(srv, __FILE__, __LINE__, "sdd",
					"unknown state:", con->fd, con->state);

			break;
		}

		if (done == -1) {
			done = 0;
		} else if (ostate == con->state) {
			done = 1;
		}
	}

	if (srv->srvconf.log_state_handling) {
		log_error_write(srv, __FILE__, __LINE__, "sds",
				"state at exit:",
				con->fd,
				connection_get_state(con->state));
	}

	r = 0;
	switch(con->state) {
	case CON_STATE_READ:
	case CON_STATE_CLOSE:
		r = FDEVENT_IN;
		break;
	case CON_STATE_WRITE:
		/* request write-fdevent only if we really need it
		 * - if we have data to write
		 * - if the socket is not writable yet
		 */
		if (!chunkqueue_is_empty(con->write_queue) &&
		    (con->is_writable == 0) &&
		    (con->traffic_limit_reached == 0)) {
			r |= FDEVENT_OUT;
		}
		/* fall through */
	case CON_STATE_READ_POST:
		if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN) {
			r |= FDEVENT_IN;
		}
		break;
	default:
		break;
	}
	if (-1 != con->fd) {
		const int events = fdevent_event_get_interest(srv->ev, con->fd);
		if (con->is_readable < 0) {
			con->is_readable = 0;
			r |= FDEVENT_IN;
		}
		if (con->is_writable < 0) {
			con->is_writable = 0;
			r |= FDEVENT_OUT;
		}
		if (r != events) {
			/* update timestamps when enabling interest in events */
			if ((r & FDEVENT_IN) && !(events & FDEVENT_IN)) {
				con->read_idle_ts = srv->cur_ts;
			}
			if ((r & FDEVENT_OUT) && !(events & FDEVENT_OUT)) {
				con->write_request_ts = srv->cur_ts;
			}
			fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, r);
		}
	}

	return 0;
}
Esempio n. 30
0
static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
	cgi_session *sess = con->plugin_ctx[p->id];

	switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
	case NETWORK_STATUS_CONNECTION_CLOSE:
		fdevent_event_del(srv->ev, sess->sock);

		/* connection closed. close the read chunkqueue. */
		sess->rb->is_closed = 1;
	case NETWORK_STATUS_SUCCESS:
		/* we got content */
		break;
	case NETWORK_STATUS_WAIT_FOR_EVENT:
		return 0;
	default:
		/* oops */
		ERROR("%s", "oops, read-pipe-read failed and I don't know why");
		return -1;
	}

	/* looks like we got some content
	*
	* split off the header from the incoming stream
	*/

	if (con->file_started == 0) {
		size_t i;
		int have_content_length = 0;

		http_response_reset(p->resp);

		/* the response header is not fully received yet,
		*
		* extract the http-response header from the rb-cq
		*/
		switch (http_response_parse_cq(sess->rb, p->resp)) {
		case PARSE_UNSET:
		case PARSE_ERROR:
			/* parsing failed */

			TRACE("%s", "response parser failed");

			con->http_status = 502; /* Bad Gateway */
			return -1;
		case PARSE_NEED_MORE:
			if (sess->rb->is_closed) {
				/* backend died before sending a header */
				con->http_status = 502; /* Bad Gateway */
				return -1;
			}
			return 0;
		case PARSE_SUCCESS:
			con->http_status = p->resp->status;

			chunkqueue_remove_finished_chunks(sess->rb);

			/* copy the http-headers */
			for (i = 0; i < p->resp->headers->used; i++) {
				const char *ign[] = { "Status", "Connection", NULL };
				size_t j;
				data_string *ds;

				data_string *header = (data_string *)p->resp->headers->data[i];

				/* some headers are ignored by default */
				for (j = 0; ign[j]; j++) {
					if (0 == strcasecmp(ign[j], header->key->ptr)) break;
				}
				if (ign[j]) continue;

				if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
					/* CGI/1.1 rev 03 - 7.2.1.2 */
					if (con->http_status == 0) con->http_status = 302;
				} else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
					have_content_length = 1;
				}

				if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
					ds = data_response_init();
				}
				buffer_copy_string_buffer(ds->key, header->key);
				buffer_copy_string_buffer(ds->value, header->value);

				array_insert_unique(con->response.headers, (data_unset *)ds);
			}

			con->file_started = 1;
			/* if Status: ... is not set, 200 is our default status-code */
			if (con->http_status == 0) con->http_status = 200;
			sess->state = CGI_STATE_READ_RESPONSE_CONTENT;

			if (con->request.http_version == HTTP_VERSION_1_1 &&
			    !have_content_length) {
				con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
		 	}

			break;
		}
	}

	/* FIXME: pass the response-header to the other plugins to
	* setup the filter-queue
	*
	* - use next-queue instead of con->write_queue
	*/

	/* copy the resopnse content */
	cgi_copy_response(srv, con, sess);

	joblist_append(srv, con);

	return 0;
}