int main() { char c1 = 'A'; char c2 = 'a'; printf("%c\n", ngx_tolower(c1));// a printf("%c\n", ngx_toupper(c2));// A return 0; }
ngx_int_t oc_smtp_parse_command(oc_smtp_session_t *s) { u_char ch, *p, *c, c0, c1, c2, c3; ngx_str_t *arg; enum { sw_start = 0, sw_spaces_before_argument, sw_argument, sw_almost_done } state; state = s->state; for (p = s->buffer->pos; p < s->buffer->last; p++) { ch = *p; switch (state) { /* SMTP command */ case sw_start: if (ch == ' ' || ch == CR || ch == LF) { c = s->buffer->start; if (p - c == 4) { c0 = ngx_toupper(c[0]); c1 = ngx_toupper(c[1]); c2 = ngx_toupper(c[2]); c3 = ngx_toupper(c[3]); if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') { s->command = OC_SMTP_HELO; } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') { s->command = OC_SMTP_EHLO; } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') { s->command = OC_SMTP_QUIT; } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') { s->command = OC_SMTP_AUTH; } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') { s->command = OC_SMTP_NOOP; } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') { s->command = OC_SMTP_MAIL; } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T') { s->command = OC_SMTP_RSET; } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T') { s->command = OC_SMTP_RCPT; } else if (c0 == 'D' && c1 == 'A' && c2 == 'T' && c3 == 'A') { s->command = OC_SMTP_DATA; } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y') { s->command = OC_SMTP_VRFY; } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N') { s->command = OC_SMTP_EXPN; } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P') { s->command = OC_SMTP_HELP; } else { goto invalid; } #if (OC_SMTP_SSL) } else if (p - c == 8) { if ((c[0] == 'S'|| c[0] == 's') && (c[1] == 'T'|| c[1] == 't') && (c[2] == 'A'|| c[2] == 'a') && (c[3] == 'R'|| c[3] == 'r') && (c[4] == 'T'|| c[4] == 't') && (c[5] == 'T'|| c[5] == 't') && (c[6] == 'L'|| c[6] == 'l') && (c[7] == 'S'|| c[7] == 's')) { s->command = OC_SMTP_STARTTLS; } else { goto invalid; } #endif } else { goto invalid; } switch (ch) { case ' ': state = sw_spaces_before_argument; break; case CR: state = sw_almost_done; break; case LF: goto done; } break; } if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { goto invalid; } break; case sw_spaces_before_argument: switch (ch) { case ' ': break; case CR: state = sw_almost_done; s->arg_end = p; break; case LF: s->arg_end = p; goto done; default: if (s->args.nelts <= 10) { state = sw_argument; s->arg_start = p; break; } goto invalid; } break; case sw_argument: switch (ch) { case ' ': case CR: case LF: arg = ngx_array_push(&s->args); if (arg == NULL) { return NGX_ERROR; } arg->len = p - s->arg_start; arg->data = s->arg_start; s->arg_start = NULL; switch (ch) { case ' ': state = sw_spaces_before_argument; break; case CR: state = sw_almost_done; break; case LF: goto done; } break; default: break; } break; case sw_almost_done: switch (ch) { case LF: goto done; default: goto invalid; } } } s->buffer->pos = p; s->state = state; return NGX_AGAIN; done: s->buffer->pos = p + 1; if (s->arg_start) { arg = ngx_array_push(&s->args); if (arg == NULL) { return NGX_ERROR; } arg->len = s->arg_end - s->arg_start; arg->data = s->arg_start; s->arg_start = NULL; } s->state = (s->command != OC_SMTP_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: s->state = sw_start; s->arg_start = NULL; return OC_SMTP_PARSE_INVALID_COMMAND; }
ngx_int_t ngx_mail_pop3_parse_command(ngx_mail_session_t *s) { u_char ch, *p, *c, c0, c1, c2, c3; ngx_str_t *arg; enum { sw_start = 0, sw_spaces_before_argument, sw_argument, sw_almost_done } state; state = s->state; for (p = s->buffer->pos; p < s->buffer->last; p++) { ch = *p; switch (state) { /* POP3 command */ case sw_start: if (ch == ' ' || ch == CR || ch == LF) { c = s->buffer->start; if (p - c == 4) { c0 = ngx_toupper(c[0]); c1 = ngx_toupper(c[1]); c2 = ngx_toupper(c[2]); c3 = ngx_toupper(c[3]); if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R') { s->command = NGX_POP3_USER; } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S') { s->command = NGX_POP3_PASS; } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P') { s->command = NGX_POP3_APOP; } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') { s->command = NGX_POP3_QUIT; } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A') { s->command = NGX_POP3_CAPA; } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') { s->command = NGX_POP3_AUTH; } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') { s->command = NGX_POP3_NOOP; #if (NGX_MAIL_SSL) } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S') { s->command = NGX_POP3_STLS; #endif } else { goto invalid; } } else { goto invalid; } switch (ch) { case ' ': state = sw_spaces_before_argument; break; case CR: state = sw_almost_done; break; case LF: goto done; } break; } if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { goto invalid; } break; case sw_spaces_before_argument: switch (ch) { case ' ': break; case CR: state = sw_almost_done; s->arg_end = p; break; case LF: s->arg_end = p; goto done; default: if (s->args.nelts <= 2) { state = sw_argument; s->arg_start = p; break; } goto invalid; } break; case sw_argument: switch (ch) { case ' ': /* * the space should be considered as part of the at username * or password, but not of argument in other commands */ if (s->command == NGX_POP3_USER || s->command == NGX_POP3_PASS) { break; } /* fall through */ case CR: case LF: arg = ngx_array_push(&s->args); if (arg == NULL) { return NGX_ERROR; } arg->len = p - s->arg_start; arg->data = s->arg_start; s->arg_start = NULL; switch (ch) { case ' ': state = sw_spaces_before_argument; break; case CR: state = sw_almost_done; break; case LF: goto done; } break; default: break; } break; case sw_almost_done: switch (ch) { case LF: goto done; default: goto invalid; } } } s->buffer->pos = p; s->state = state; return NGX_AGAIN; done: s->buffer->pos = p + 1; if (s->arg_start) { arg = ngx_array_push(&s->args); if (arg == NULL) { return NGX_ERROR; } arg->len = s->arg_end - s->arg_start; arg->data = s->arg_start; s->arg_start = NULL; } s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: s->state = sw_start; s->arg_start = NULL; return NGX_MAIL_PARSE_INVALID_COMMAND; }
static ngx_int_t ngx_lua_http_parse_args(lua_State *l, ngx_lua_thread_t *thr, ngx_lua_http_ctx_t *ctx) { int top; char *errstr; u_char *p, *last; ngx_str_t str; ngx_keyval_t *header; ngx_log_debug0(NGX_LOG_DEBUG_CORE, thr->log, 0, "lua http parse args"); if (!lua_istable(l, 1)) { return luaL_error(l, "invalid the first argument, must be a table"); } top = lua_gettop(l); lua_getfield(l, 1, "method"); str.data = (u_char *) luaL_optlstring(l, -1, "GET", &str.len); ctx->method.len = str.len; ctx->method.data = ngx_pstrdup(ctx->pool, &str); if (ctx->method.data == NULL) { errstr = "ngx_pstrdup() failed"; goto error; } lua_getfield(l, 1, "version"); str.data = (u_char *) luaL_optlstring(l, -1, "1.1", &str.len); ctx->version.len = str.len; ctx->version.data = ngx_pstrdup(ctx->pool, &str); if (ctx->version.data == NULL) { errstr = "ngx_pstrdup() failed"; goto error; } lua_getfield(l, 1, "url"); str.data = (u_char *) luaL_checklstring(l, -1, &str.len); ctx->u.url.len = str.len; ctx->u.url.data = ngx_pstrdup(ctx->pool, &str); if (ctx->u.url.data == NULL) { errstr = "ngx_pstrdup() failed"; goto error; } lua_getfield(l, 1, "headers"); if (!lua_isnil(l, -1)) { if (!lua_istable(l, -1)) { return luaL_error(l, "invalid value of the argument \"headers\"" ", must be a table"); } lua_pushnil(l); while (lua_next(l, -2)) { header = ngx_array_push(&ctx->headers); if (header == NULL) { errstr = "ngx_array_push() failed"; goto error; } str.data = (u_char *) luaL_checklstring(l, -2, &str.len); header->key.len = str.len; header->key.data = ngx_pstrdup(ctx->pool, &str); header->key.data[0] = ngx_toupper(header->key.data[0]); for (p = header->key.data, last = p + header->key.len; p < last - 1; p++) { if (*p == '_') { *p = '-'; p[1] = ngx_toupper(p[1]); } } str.data = (u_char *) luaL_checklstring(l, -1, &str.len); header->value.len = str.len; header->value.data = ngx_pstrdup(ctx->pool, &str); lua_pop(l, 1); } } lua_getfield(l, 1, "body"); str.data = (u_char *) luaL_optlstring(l, -1, "", &str.len); ctx->body.len = str.len; ctx->body.data = ngx_pstrdup(ctx->pool, &str); if (ctx->body.data == NULL) { errstr = "ngx_pstrdup() failed"; goto error; } lua_settop(l, top); ctx->connect_timeout = (ngx_msec_t) luaL_optnumber(l, 2, 60000); ctx->send_timeout = (ngx_msec_t) luaL_optnumber(l, 3, 60000); ctx->read_timeout = (ngx_msec_t) luaL_optnumber(l, 4, 60000); return NGX_OK; error: lua_settop(l, top); lua_pushboolean(l, 0); lua_pushstring(l, errstr); return NGX_ERROR; }
SV *ngx_http_psgi_create_env(pTHX_ ngx_http_request_t *r, char *app) { ngx_list_part_t *part; ngx_table_elt_t *h; ngx_uint_t i, c, x; SV *_version[2]; AV *version; HV* env = newHV(); /* PSGI version 1.0, arrayref [1,0] */ _version[0] = newSViv(1); _version[1] = newSViv(0); version = av_make(2, _version); SvREFCNT_dec(_version[0]); SvREFCNT_dec(_version[1]); hv_store(env, "psgi.version", sizeof("psgi.version")-1, newRV_noinc((SV*)version), 0); /* FIXME: after any of this two operations $! is set to 'Inappropriate ioctl for device' */ SV *errors_h = PerlIONginxError_newhandle(aTHX_ r); if (errors_h == NULL) return NULL; hv_store(env, "psgi.errors", sizeof("psgi.errors")-1, errors_h, 0); SV *input_h = PerlIONginxInput_newhandle(aTHX_ r); if (input_h == NULL) return NULL; hv_store(env, "psgi.input", sizeof("psgi.input")-1, input_h, 0); /* Detect scheme. * TODO: Check if only http and https schemes allowed here. What about ws and others? * FIXME: mb nginx should parse scheme in safe way: [a-z][a-z0-9\=\0\.]* allowed to be valid scheme (rfc3986) * but nginx allows only [a-z]+ */ #if (NGX_HTTP_SSL) char *scheme; if (r->connection->ssl) { scheme = "https"; } else { scheme = "http"; } hv_store(env, "psgi.url_scheme", sizeof("psgi.url_scheme")-1, newSVpv(scheme, 0), 0); #else hv_store(env, "psgi.url_scheme", sizeof("psgi.url_scheme")-1, newSVpv("http", 0), 0); #endif // Buffered body in file if (r->request_body != NULL && r->request_body->temp_file != NULL) { hv_store(env, "psgix.input.buffered", sizeof("psgix.input.buffered")-1, newSViv(1), 0); } /* port defined in first line of HTTP request and parsed by nginx */ if (r->port_start) { STRLEN port_len = r->port_end - r->port_start; hv_store(env, "SERVER_PORT", sizeof("SERVER_PORT")-1, newSVpv((char *)r->port_start, port_len), 0); } else { /* copypasted from ngx_http_variables.c: get port from nginx conf */ /* TODO: Maybe reuse code from ngx_http_variables.c is a good idea? */ ngx_uint_t port; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif u_char *strport; if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) { // TODO: Throw error return NULL; } strport = ngx_pnalloc(r->pool, sizeof("65535") - 1); if (strport == NULL) { return NULL; } switch (r->connection->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->local_sockaddr; port = ntohs(sin->sin_port); break; } if (port > 0 && port < 65536) { hv_store(env, "SERVER_PORT", sizeof("SERVER_PORT")-1, newSVuv(port), 0); } else { hv_store(env, "SERVER_PORT", sizeof("SERVER_PORT")-1, newSVpv("", 0), 0); } } hv_store(env, "SERVER_PROTOCOL", sizeof("SERVER_PROTOCOL")-1, newSVpv((char *)r->http_protocol.data, r->http_protocol.len), 0); if (r->headers_in.content_length_n != -1) { hv_store(env, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1, newSViv(r->headers_in.content_length_n), 0); } if (r->headers_in.content_type != NULL) { hv_store(env, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1, newSVpv((char*)r->headers_in.content_type->value.data, r->headers_in.content_type->value.len), 0); } hv_store(env, "REQUEST_URI", sizeof("REQUEST_URI")-1, newSVpv((char *)r->unparsed_uri.data, r->unparsed_uri.len), 0); /* TODO: SCRIPT_NAME should be string matched by 'location' value in nginx.conf */ hv_store(env, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1, newSVpv("", 0), 0); /* FIXME: * PATH_INFO should be relative to SCRIPT_NAME (current 'location') path in nginx.conf * How to achieve this? Should I allow psgi only in 'exact match' locations? * It would be hard to find PATH_INFO for locations like "location ~ /(foo|bar)/.* { }". Or it wouldn't? */ hv_store(env, "PATH_INFO", sizeof("PATH_INFO")-1, newSVpv((char *)r->uri.data, r->uri.len), 0); hv_store(env, "REQUEST_METHOD", sizeof("REQUEST_METHOD")-1, newSVpv((char *)r->method_name.data, r->method_name.len), 0); if (r->args.len > 0) { hv_store(env, "QUERY_STRING", sizeof("QUERY_STRING")-1, newSVpv((char *)r->args.data, r->args.len), 0); } else { hv_store(env, "QUERY_STRING", sizeof("QUERY_STRING")-1, newSVpv("", 0), 0); } if (r->host_start && r->host_end) { hv_store(env, "SERVER_NAME", sizeof("SERVER_NAME")-1, newSVpv((char *)r->host_start, r->host_end - r->host_start), 0); } else { ngx_http_core_srv_conf_t *cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); hv_store(env, "SERVER_NAME", sizeof("SERVER_NAME")-1, newSVpv((char *)cscf->server_name.data, cscf->server_name.len), 0); } hv_store(env, "REMOTE_ADDR", sizeof("REMOTE_ADDR")-1, newSVpv((char *)r->connection->addr_text.data, r->connection->addr_text.len), 0); /* TODO * * psgi.multithread * psgi.multiprocess */ part = &r->headers_in.headers.part; h = part->elts; c = 0; for (i = 0; /* void */ ; i++) { ngx_str_t name; u_char *p; if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } /* The environment MUST NOT contain keys named HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH. * PSGI 1.09_3 */ if (ngx_strncasecmp(h[i].key.data, (u_char*)"CONTENT-LENGTH", h[i].key.len) == 0) { continue; } if (ngx_strncasecmp(h[i].key.data, (u_char*)"CONTENT-TYPE", h[i].key.len) == 0) { continue; } p = ngx_pnalloc(r->pool, sizeof("HTTP_") - 1 + h[i].key.len); if (p == NULL) { return NULL; } name.data = p; name.len = sizeof("HTTP_") + h[i].key.len -1 ; p = ngx_copy(p, (u_char*)"HTTP_", sizeof("HTTP_")-1); p = ngx_copy(p, h[i].key.data, h[i].key.len ); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Set env header: '%s' => '%s'", h[i].key.data, h[i].value.data); x = h[i].key.len + sizeof("HTTP_"); while (x > 0) { if (name.data[x] == '-') { name.data[x] = '_'; } else { name.data[x] = ngx_toupper(name.data[x]); } x--; } SV **exists = hv_fetch(env, (char*)name.data, name.len, 0); if (exists == NULL) { hv_store(env, (char *)name.data, name.len, newSVpv((char *)h[i].value.data, h[i].value.len), 0); } else { /* join ',', @values; * FIXME: Can I do this better */ SV *newval = newSVpvf("%s,%s", SvPV_nolen(*exists), h[i].value.data); hv_store(env, (char *)name.data, name.len, newval, 0); } c += 2; } return newRV_noinc((SV*)env); }