<commit_before>package org.jruby.jubilee;

import io.netty.handler.codec.http.HttpHeaders;
import org.jruby.*;
import org.jruby.jubilee.utils.RubyHelper;
import org.vertx.java.core.MultiMap;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.core.http.HttpVersion;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

public class RackEnvironment {

    // When adding a key to the enum be sure to add its RubyString equivalent
    // to populateRackKeyMap below
    static enum RACK_KEY {
        RACK_INPUT, RACK_ERRORS, REQUEST_METHOD, SCRIPT_NAME,
        PATH_INFO, QUERY_STRING, SERVER_NAME, SERVER_PORT,
        CONTENT_TYPE, REQUEST_URI, REMOTE_ADDR, URL_SCHEME,
        VERSION, MULTITHREAD, MULTIPROCESS, RUN_ONCE, CONTENT_LENGTH,
        HTTPS, HTTP_VERSION, HIJACK_P, HIJACK//, HIJACK_IO
    }

    static final int NUM_RACK_KEYS = RACK_KEY.values().length;

    public RackEnvironment(final Ruby runtime) throws IOException {
        this.runtime = runtime;
        this.netSocketClass = (RubyClass) runtime.getClassFromPath("Jubilee::NetSocket");
        rackVersion = RubyArray.newArray(runtime, RubyFixnum.one(runtime), RubyFixnum.four(runtime));
        errors = new RubyIO(runtime, runtime.getErr());
        errors.setAutoclose(false);

        populateRackKeyMap();
    }

    private void populateRackKeyMap() {
        putRack("rack.input", RACK_KEY.RACK_INPUT);
        putRack("rack.errors", RACK_KEY.RACK_ERRORS);
        putRack("REQUEST_METHOD", RACK_KEY.REQUEST_METHOD);
        putRack("SCRIPT_NAME", RACK_KEY.SCRIPT_NAME);
        putRack("PATH_INFO", RACK_KEY.PATH_INFO);
        putRack("QUERY_STRING", RACK_KEY.QUERY_STRING);
        putRack("SERVER_NAME", RACK_KEY.SERVER_NAME);
        putRack("SERVER_PORT", RACK_KEY.SERVER_PORT);
        putRack("HTTP_VERSION", RACK_KEY.HTTP_VERSION);
        putRack("CONTENT_TYPE", RACK_KEY.CONTENT_TYPE);
        putRack("REQUEST_URI", RACK_KEY.REQUEST_URI);
        putRack("REMOTE_ADDR", RACK_KEY.REMOTE_ADDR);
        putRack("rack.url_scheme", RACK_KEY.URL_SCHEME);
        putRack("rack.version", RACK_KEY.VERSION);
        putRack("rack.multithread", RACK_KEY.MULTITHREAD);
        putRack("rack.multiprocess", RACK_KEY.MULTIPROCESS);
        putRack("rack.run_once", RACK_KEY.RUN_ONCE);
        putRack("rack.hijack?", RACK_KEY.HIJACK_P);
        putRack("rack.hijack", RACK_KEY.HIJACK);
        // putRack("rack.hijack_io", RACK_KEY.HIJACK_IO); Don't have to be lazy, since once rack.hijack is called, the io
        // object has to be required by the caller.
        putRack("CONTENT_LENGTH", RACK_KEY.CONTENT_LENGTH);
        putRack("HTTPS", RACK_KEY.HTTPS);
    }

    private void putRack(String key, RACK_KEY value) {
        rackKeyMap.put(RubyHelper.toUsAsciiRubyString(runtime, key), value);
    }

    public RubyHash getEnv(final HttpServerRequest request,
                           final RackInput input,
                           final boolean isSSL) throws IOException {
        MultiMap headers = request.headers();
        final RackEnvironmentHash env = new RackEnvironmentHash(runtime, headers, rackKeyMap);
        env.lazyPut(RACK_KEY.RACK_INPUT, input, false);
        env.lazyPut(RACK_KEY.RACK_ERRORS, errors, false);

        String pathInfo = request.path();

        String scriptName = "";
        String[] hostInfo = getHostInfo(request.headers().get(Const.HOST));

        env.lazyPut(RACK_KEY.REQUEST_METHOD, request.method(), true);
        env.lazyPut(RACK_KEY.SCRIPT_NAME, scriptName, false);
        env.lazyPut(RACK_KEY.PATH_INFO, pathInfo, false);
        env.lazyPut(RACK_KEY.QUERY_STRING, orEmpty(request.query()), false);
        env.lazyPut(RACK_KEY.SERVER_NAME, hostInfo[0], false);
        env.lazyPut(RACK_KEY.SERVER_PORT, hostInfo[1], true);
        env.lazyPut(RACK_KEY.HTTP_VERSION,
                request.version() == HttpVersion.HTTP_1_1 ? Const.HTTP_11 : Const.HTTP_10, true);
        env.lazyPut(RACK_KEY.CONTENT_TYPE, headers.get(HttpHeaders.Names.CONTENT_TYPE), true);
        env.lazyPut(RACK_KEY.REQUEST_URI, request.uri(), false);
        env.lazyPut(RACK_KEY.REMOTE_ADDR, getRemoteAddr(request), true);
        env.lazyPut(RACK_KEY.URL_SCHEME, isSSL ? Const.HTTPS : Const.HTTP, true);
        env.lazyPut(RACK_KEY.VERSION, rackVersion, false);
        env.lazyPut(RACK_KEY.MULTITHREAD, runtime.getTrue(), false);
        env.lazyPut(RACK_KEY.MULTIPROCESS, runtime.getFalse(), false);
        env.lazyPut(RACK_KEY.RUN_ONCE, runtime.getFalse(), false);

        // Hijack handling
        env.lazyPut(RACK_KEY.HIJACK_P, runtime.getTrue(), false);
        env.lazyPut(RACK_KEY.HIJACK, new RubyCallable.Callable() {
            @Override
            public void call() {
                env.put("rack.hijack_io", new RubyNetSocket(runtime, netSocketClass, request.netSocket()));
            }
        }, false);


        final int contentLength = getContentLength(headers);
        if (contentLength >= 0) {
            env.lazyPut(RACK_KEY.CONTENT_LENGTH, contentLength + "", true);
        }

        if (isSSL) {
            env.lazyPut(RACK_KEY.HTTPS, "on", true);
        }

        return env;
    }


    public String[] getHostInfo(String host) {
        String[] hostInfo;
        if (host != null) {
            int colon = host.indexOf(":");
            if (colon > 0)<commit_msg>construct proper RubyProc object for rack.hijack<commit_after>package org.jruby.jubilee;

import io.netty.handler.codec.http.HttpHeaders;
import org.jruby.*;
import org.jruby.jubilee.utils.RubyHelper;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.vertx.java.core.MultiMap;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.core.http.HttpVersion;
import org.vertx.java.core.net.NetSocket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

public class RackEnvironment {

    // When adding a key to the enum be sure to add its RubyString equivalent
    // to populateRackKeyMap below
    static enum RACK_KEY {
        RACK_INPUT, RACK_ERRORS, REQUEST_METHOD, SCRIPT_NAME,
        PATH_INFO, QUERY_STRING, SERVER_NAME, SERVER_PORT,
        CONTENT_TYPE, REQUEST_URI, REMOTE_ADDR, URL_SCHEME,
        VERSION, MULTITHREAD, MULTIPROCESS, RUN_ONCE, CONTENT_LENGTH,
        HTTPS, HTTP_VERSION, HIJACK_P, HIJACK//, HIJACK_IO
    }

    static final int NUM_RACK_KEYS = RACK_KEY.values().length;

    public RackEnvironment(final Ruby runtime) throws IOException {
        this.runtime = runtime;
        this.netSocketClass = (RubyClass) runtime.getClassFromPath("Jubilee::NetSocket");
        rackVersion = RubyArray.newArray(runtime, RubyFixnum.one(runtime), RubyFixnum.four(runtime));
        errors = new RubyIO(runtime, runtime.getErr());
        errors.setAutoclose(false);

        populateRackKeyMap();
    }

    private void populateRackKeyMap() {
        putRack("rack.input", RACK_KEY.RACK_INPUT);
        putRack("rack.errors", RACK_KEY.RACK_ERRORS);
        putRack("REQUEST_METHOD", RACK_KEY.REQUEST_METHOD);
        putRack("SCRIPT_NAME", RACK_KEY.SCRIPT_NAME);
        putRack("PATH_INFO", RACK_KEY.PATH_INFO);
        putRack("QUERY_STRING", RACK_KEY.QUERY_STRING);
        putRack("SERVER_NAME", RACK_KEY.SERVER_NAME);
        putRack("SERVER_PORT", RACK_KEY.SERVER_PORT);
        putRack("HTTP_VERSION", RACK_KEY.HTTP_VERSION);
        putRack("CONTENT_TYPE", RACK_KEY.CONTENT_TYPE);
        putRack("REQUEST_URI", RACK_KEY.REQUEST_URI);
        putRack("REMOTE_ADDR", RACK_KEY.REMOTE_ADDR);
        putRack("rack.url_scheme", RACK_KEY.URL_SCHEME);
        putRack("rack.version", RACK_KEY.VERSION);
        putRack("rack.multithread", RACK_KEY.MULTITHREAD);
        putRack("rack.multiprocess", RACK_KEY.MULTIPROCESS);
        putRack("rack.run_once", RACK_KEY.RUN_ONCE);
        putRack("rack.hijack?", RACK_KEY.HIJACK_P);
        putRack("rack.hijack", RACK_KEY.HIJACK);
        // putRack("rack.hijack_io", RACK_KEY.HIJACK_IO); Don't have to be lazy, since once rack.hijack is called, the io
        // object has to be required by the caller.
        putRack("CONTENT_LENGTH", RACK_KEY.CONTENT_LENGTH);
        putRack("HTTPS", RACK_KEY.HTTPS);
    }

    private void putRack(String key, RACK_KEY value) {
        rackKeyMap.put(RubyHelper.toUsAsciiRubyString(runtime, key), value);
    }

    public RubyHash getEnv(final HttpServerRequest request,
                           final RackInput input,
                           final boolean isSSL) throws IOException {
        MultiMap headers = request.headers();
        final RackEnvironmentHash env = new RackEnvironmentHash(runtime, headers, rackKeyMap);
        env.lazyPut(RACK_KEY.RACK_INPUT, input, false);
        env.lazyPut(RACK_KEY.RACK_ERRORS, errors, false);

        String pathInfo = request.path();

        String scriptName = "";
        String[] hostInfo = getHostInfo(request.headers().get(Const.HOST));

        env.lazyPut(RACK_KEY.REQUEST_METHOD, request.method(), true);
        env.lazyPut(RACK_KEY.SCRIPT_NAME, scriptName, false);
        env.lazyPut(RACK_KEY.PATH_INFO, pathInfo, false);
        env.lazyPut(RACK_KEY.QUERY_STRING, orEmpty(request.query()), false);
        env.lazyPut(RACK_KEY.SERVER_NAME, hostInfo[0], false);
        env.lazyPut(RACK_KEY.SERVER_PORT, hostInfo[1], true);
        env.lazyPut(RACK_KEY.HTTP_VERSION,
                request.version() == HttpVersion.HTTP_1_1 ? Const.HTTP_11 : Const.HTTP_10, true);
        env.lazyPut(RACK_KEY.CONTENT_TYPE, headers.get(HttpHeaders.Names.CONTENT_TYPE), true);
        env.lazyPut(RACK_KEY.REQUEST_URI, request.uri(), false);
        env.lazyPut(RACK_KEY.REMOTE_ADDR, getRemoteAddr(request), true);
        env.lazyPut(RACK_KEY.URL_SCHEME, isSSL ? Const.HTTPS : Const.HTTP, true);
        env.lazyPut(RACK_KEY.VERSION, rackVersion, false);
        env.lazyPut(RACK_KEY.MULTITHREAD, runtime.getTrue(), false);
        env.lazyPut(RACK_KEY.MULTIPROCESS, runtime.getFalse(), false);
        env.lazyPut(RACK_KEY.RUN_ONCE, runtime.getFalse(), false);

        // Hijack handling
        env.lazyPut(RACK_KEY.HIJACK_P, runtime.getTrue(), false);
        env.lazyPut(RACK_KEY.HIJACK, hijackProc(env, request.netSocket()), false);


        final int contentLength = getContentLength(headers);
        if (contentLength >= 0) {
            env.lazyPut(RACK_KEY.CONTENT_LENGTH, contentLength + "", true);
        }

        if (isSSL) {
            env.lazyPut(RACK_KEY.HTTPS, "on", true);
        }

        return env;
    }

    private IRubyObject hijackProc(final RackEnvironmentHash env, final NetSocket sock) {
        CompiledBlockCallback19 callback = new CompiledBlockCallback19() {
            @Override
            public IRubyObject call(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
                RubyNetSocket rubyNetSocket = new RubyNetSocket(context.runtime, netSocketClass, sock);
                env.put("rack.hijack_io", rubyNetSocket);
                return rubyNetSocket;
            }

            @Override
            public String getFile() {
                return null;
            }

            @Override
            public int getLine() {
                return 0;
            }
        };
        BlockBody body = CompiledBlockLight19.newCompiledBlockLight(Arity.NO_ARGUMENTS, runtime.getStaticScopeFactory().getDummyScope(), callback, false, 0, new String[]{});
        Block b = new Block(body, runtime.newBinding().getBinding());

        return RubyProc.newProc(runtime, b, Block.Type.LAMBDA);
    }

    public String[] getHostInfo(String host) {
        String[] hostInfo;
        if (host != null) {
            int colon = host.indexOf(":");
            if (colon > 0)
{'fraction_non_alphanumeric': 0.11382457326347811, 'fraction_numerical': 0.0023660638837248605, 'mean_word_length': 3.076817085773338, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5209187', 'n_tokens_mistral': 4010, 'n_tokens_neox': 3839, 'n_words': 676}