int parse_url(const char *url, struct http_parser_url *u, http_request *request) { if (url == NULL) { return -1; } char real_url[1024] = {0}; if ((is_match_pattern(url, REGEX_URL_SCHEME)) != 0) { snprintf(real_url, 1024, "http://%s", url); } else { snprintf(real_url, 1024, "%s", url); } SCREEN(SCREEN_YELLOW, stdout, "Request url:\t\t"); SCREEN(SCREEN_DARK_GREEN, stdout, "%s\n", real_url); int url_len = strlen(real_url); int ret = http_parser_parse_url(real_url, url_len, 0, u); if (ret != 0) { printf("Invalid request url!\n"); return -1; } char strport[64] = {0}; for (unsigned i = 0; i < UF_MAX; i++) { if ((u->field_set & (1 << i)) == 0) { continue; } switch (i) { case UF_SCHEMA: snprintf(request->scheme, 16, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); break; case UF_HOST: snprintf(request->host, 256, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); break; case UF_PORT: snprintf(strport, 64, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); request->port = atoi(strport); break; case UF_PATH: snprintf(request->path, 256, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); break; case UF_QUERY: snprintf(request->querystring, 1024, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); break; case UF_FRAGMENT: snprintf(request->fragment, 256, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); break; case UF_USERINFO: snprintf(request->userinfo, 256, "%.*s", u->field_data[i].len, real_url + u->field_data[i].off); break; default: break; } } return 0; }
const SpObject *SpVM::call_function(const std::string &name, const SpFunction *func, const SpExpr *call_expr, SpEnv *env) { // now, evaluate the arguments in a new scope // this is because Spooner is lexically scoped, so any this function call // can only access its arguments std::unique_ptr<SpEnv> call_env(new SpEnv()); // check if the correct number of arguments are provided if (call_expr->length() - 1 != func->num_arguments()) RUNTIME_ERROR_F("Function call to '%s' requires %lu arguments, " "but %d given", name.c_str(), func->num_arguments(), call_expr->length() - 1); size_t arg_index = 0; for (auto it = call_expr->cbegin(); it != call_expr->cend(); ++it, arg_index++) { // if there is a pattern for this argument if (arg_index < func->pattern()->length()) { // need to handle the quote pattern specially if (func->pattern(arg_index)->type() == T_NAME) { const char *name = ((SpName *)func->pattern(arg_index))->value(); if (!strcmp(name, "quote")) { // we need to quote this argument and not evaluate it call_env->bind_name(func->arguments(arg_index), new SpExprObject(*it)); } else if (!strcmp(name, "_")) { // wildcards match anything call_env->bind_name(func->arguments(arg_index), eval(*it, env)); } else { // TODO: allow names in patterns RUNTIME_ERROR("Names cannot be used in patterns yet..."); } } else { // check if this pattern matches const SpObject *arg_result = eval(*it, env); if (is_match_pattern(func->pattern(arg_index), arg_result)) { // good, we'll bind this argument call_env->bind_name(func->arguments(arg_index), arg_result); } else { RUNTIME_ERROR_F("Arguments in function call to '%s' do not match any patterns", name.c_str()); } } } else { // no pattern means anything matches call_env->bind_name(func->arguments(arg_index), eval(*it, env)); } } // call the function (either natively or in the VM) using the new environment return func->is_native() ? call_native_function((SpNativeFunction *)func, call_env.get()) : call_function_with_env(func, call_env.get()); }
void compose_request_buffer(http_request* request) { char *buffer = calloc(1, REQUEST_BUFFER_SIZE * sizeof(char)); ASSERT_ALLOCATE(buffer); size_t offset = 0; /* Start line */ int bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s ", get_method_name(request->method)); offset += bytes; /* Path, querystring, fragment */ if (strlen(request->path) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s", request->path); offset += bytes; } if (strlen(request->querystring) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "?%s", request->querystring); offset += bytes; } if (strlen(request->fragment) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "#%s ", request->fragment); offset += bytes; } bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, " %s\r\n", HTTP_1_1); offset += bytes; /* Start line ends here */ bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Accept: */*\r\n"); offset += bytes; /* Host */ if (is_match_pattern(request->host, REGEX_IPV4) != 0 && strcasecmp(request->host, "localhost") != 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Host: %s\r\n", request->host); offset += bytes; } else { char host[256] = {'\0'}; get_header_value("Host", request->additional_header, host); if (strlen(host) == 0) { if (request->port == PORT_HTTP) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Host: %s\r\n", request->host); offset += bytes; } else { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Host: %s:%d\r\n", request->host, request->port); offset += bytes; } } } if (request->http_keep_alive == HTTP_KEEP_ALIVE) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Connection: keep-alive\r\n"); offset += bytes; } if (strlen(request->bodydata) != 0 && request->file_upload != NULL) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Type: multipart/form-data; boundary=%s\r\n", boundary); offset += bytes; } else if (strlen(request->content_type) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Type: %s\r\n", request->content_type); offset += bytes; } if (request->additional_header != NULL) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s\r\n", request->additional_header); offset += bytes; } if (!(strlen(request->bodydata) != 0 && request->file_upload != NULL)) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Length: %d\r\n", request->content_length); offset += bytes; /* Header ends here */ bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "\r\n"); offset += bytes; SCREEN(SCREEN_BLUE, stdout, "Http request header:\n"); SCREEN(SCREEN_GREEN, stdout, "%s", buffer); if (request->file_upload != NULL) { int fd = open(request->file_upload, O_RDONLY); if (fd < 0) { perror("open(2)"); exit(EXIT_FAILURE); } bytes = read(fd, buffer + offset, request->content_length); if (bytes != request->content_length) { SCREEN(SCREEN_RED, stderr, "Cannot read your input file: %s.\n", request->file_upload); exit(EXIT_FAILURE); } offset += bytes; } else if (strlen(request->bodydata) != 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s", request->bodydata); offset += bytes; } } else { /* Two multi-part */ /* We need to caculate Content-Length again */ char *extrabuffer = (char *) calloc(1, (REQUEST_BUFFER_SIZE) * sizeof(char)); ASSERT_ALLOCATE(extrabuffer); int bodyoffset = 0; bytes = snprintf(extrabuffer + bodyoffset, REQUEST_BUFFER_SIZE - bodyoffset, "%s\r\nContent-Disposition: form-data; name=\"img\", filename=\"%s\"\r\nContent-Type: image/jpeg\r\n\r\n", boundary, basename(request->file_upload)); bodyoffset += bytes; int fd = open(request->file_upload, O_RDONLY); if (fd < 0) { perror("open(2)"); exit(EXIT_FAILURE); } bytes = read(fd, extrabuffer + bodyoffset, request->file_size); if (bytes != request->file_size) { SCREEN(SCREEN_RED, stderr, "Cannot read your input file: %s.\n", request->file_upload); exit(EXIT_FAILURE); } bodyoffset += request->file_size; bytes = snprintf(extrabuffer + bodyoffset, REQUEST_BUFFER_SIZE - bodyoffset, "\r\n%s\r\nContent-Disposition: form-data; name=\"json\"\r\n\r\n%s\r\n%s\r\n", boundary, request->bodydata, boundary); bodyoffset += bytes; bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Length: %d\r\n", bodyoffset); offset += bytes; /* Header ends here */ bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "\r\n"); offset += bytes; SCREEN(SCREEN_BLUE, stdout, "Http request header:\n"); SCREEN(SCREEN_GREEN, stdout, "%s", buffer); memmove(buffer + offset, extrabuffer, bodyoffset); offset += bodyoffset; } request->send_buffer = buffer; request->total_length = offset; return; }