Example #1
0
int main()
{
	char c1 = 'A';
	char c2 = 'a';

	printf("%c\n", ngx_tolower(c1));// a
	printf("%c\n", ngx_toupper(c2));// A

	return 0;
}
Example #2
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;
}
Example #4
0
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;
}
Example #5
0
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);
}