All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rawhttp.cli.Main Maven / Gradle / Ivy

package rawhttp.cli;

import com.athaydes.rawhttp.cli.Versions;
import com.athaydes.rawhttp.reqinedit.ReqInEditEntry;
import com.athaydes.rawhttp.reqinedit.ReqInEditParser;
import com.athaydes.rawhttp.reqinedit.ReqInEditUnit;
import com.athaydes.rawhttp.reqinedit.js.JsEnvironment;
import rawhttp.cli.client.RawHttpCliClient;
import rawhttp.core.RawHttp;
import rawhttp.core.RawHttpOptions;
import rawhttp.core.RawHttpRequest;
import rawhttp.core.body.FileBody;
import rawhttp.core.body.HttpMessageBody;
import rawhttp.core.body.StringBody;
import rawhttp.core.client.RedirectingRawHttpClient;
import rawhttp.core.errors.InvalidHttpRequest;
import rawhttp.core.server.RawHttpServer;
import rawhttp.core.server.TcpRawHttpServer;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.List;
import java.util.Optional;
import java.util.Properties;

public class Main {

    private static class CliError {
        final ErrorCode code;
        final String message;

        CliError(ErrorCode code, String message) {
            this.code = code;
            this.message = message;
        }
    }

    private enum ErrorCode {
        BAD_USAGE, // 1
        INVALID_HTTP_REQUEST, // 2
        UNEXPECTED_ERROR, // 3
        IO_EXCEPTION, // 4
        USER_TEST_FAILURE, // 5
    }

    private static final RawHttp HTTP = new RawHttp(RawHttpOptions.newBuilder()
            .allowIllegalStartLineCharacters()
            .build());

    public static void main(String[] args) {
        CliError error;
        try {
            error = OptionsParser.parse(args).run(
                    clientOptions -> clientOptions.run(
                            Main::sendRequestFromSysIn,
                            Main::sendRequestFromFile,
                            Main::sendRequestFromText),
                    Main::runHttpFile,
                    Main::serve,
                    Main::showUsage);
        } catch (OptionsException e) {
            error = new CliError(ErrorCode.BAD_USAGE, e.getMessage());
        } catch (InvalidHttpRequest e) {
            error = new CliError(ErrorCode.INVALID_HTTP_REQUEST, e.toString());
        } catch (Exception e) {
            error = new CliError(ErrorCode.UNEXPECTED_ERROR, e.toString());
        }
        if (error != null) {
            System.err.println(error.message);
            System.exit(1 + error.code.ordinal());
        }
    }

    private static CliError showUsage(HelpOptions options) {
        System.out.println("=============== RawHTTP CLI ===============");
        System.out.println(" https://github.com/renatoathaydes/rawhttp");
        System.out.println(" rawhttp-cli  version: " + Versions.CLI_VERSION);
        System.out.println(" rawhttp-core version: " + Versions.CORE_VERSION);
        System.out.println("===========================================");

        switch (options) {
            case GENERAL:
                System.out.println("\n" +
                        "RawHTTP CLI is a utility to send and receive HTTP messages.\n" +
                        "The following sub-commands are available:\n" +
                        "\n" +
                        "  send    - sends a HTTP request\n" +
                        "  run     - runs a HTTP file in the IntelliJ format.\n" +
                        "  serve   - serves the contents of a local directory via HTTP.\n" +
                        "  help    - shows this message or help for a specific sub-command.\n" +
                        "\n" +
                        "Send Command Usage:\n" +
                        "  rawhttp send [options]\n" +
                        "Run Command Usage:\n" +
                        "  rawhttp run  [options]\n" +
                        "\n" +
                        "Serve Command Usage:\n" +
                        "  rawhttp serve  [options]\n" +
                        "\n" +
                        "Help Command Usage:\n" +
                        "  rawhttp help send|serve\n" +
                        "\n" +
                        "Detailed documentation at https://renatoathaydes.github.io/rawhttp\n");
                break;
            case SEND:
                System.out.println("\n" +
                        "Send sub-command Help.\n" +
                        "\n" +
                        "The 'send' sub-command is used to send out a single HTTP request.\n" +
                        "\n" +
                        "Usage:\n" +
                        "  rawhttp send [options]\n" +
                        "\n" +
                        "Options:\n" +
                        "  * -f --file \n" +
                        "      read request from a file\n" +
                        "  * -t --text \n" +
                        "      read request as text\n" +
                        "  * -p --print-response-mode  [options]\n" +
                        "\n" +
                        "Options:\n" +
                        "  * -l --log-requests\n" +
                        "      log requests received by the server\n" +
                        "  * -m --media-types \n" +
                        "      use custom Media-Type mappings\n" +
                        "  * -p --port \n" +
                        "      the port to listen on\n" +
                        "  * -r --root-path \n" +
                        "      the path to use as the root path (not incl. in file path, only URL)\n");
                break;
            default:
                return new CliError(ErrorCode.UNEXPECTED_ERROR, "Help option is not covered: " + options);
        }
        return null;
    }

    private static CliError sendRequestFromText(String request, SendRequestOptions options) {
        return sendRequest(HTTP.parseRequest(request), options);
    }

    private static CliError sendRequestFromSysIn(SendRequestOptions options) {
        try {
            return sendRequest(HTTP.parseRequest(System.in), options);
        } catch (IOException e) {
            return new CliError(ErrorCode.IO_EXCEPTION, e.toString());
        }
    }

    private static CliError sendRequestFromFile(File file, SendRequestOptions options) {
        try (InputStream fileStream = Files.newInputStream(file.toPath())) {
            return sendRequest(HTTP.parseRequest(fileStream), options);
        } catch (IOException e) {
            return new CliError(ErrorCode.IO_EXCEPTION, e.toString());
        }
    }

    private static CliError sendRequest(RawHttpRequest request, SendRequestOptions options) {
        if (options.getRequestBody().isPresent()) {
            HttpMessageBody requestBody = options.getRequestBody().get().run(
                    FileBody::new,
                    StringBody::new);

            if (requestBody instanceof FileBody) {
                File file = ((FileBody) requestBody).getFile();
                if (file.isDirectory()) {
                    return new CliError(ErrorCode.UNEXPECTED_ERROR, "Request body file cannot be a directory: " + file);
                }
                if (!file.isFile()) {
                    return new CliError(ErrorCode.UNEXPECTED_ERROR, "Request body file does not exist: " + file);
                }
            }
            request = request.withBody(requestBody);
        }

        try (RawHttpCliClient client = RawHttpCliClient.create(options.logRequest,
                options.printResponseMode, options.ignoreTlsCertificate)) {
            client.send(request);
        } catch (IOException e) {
            return new CliError(ErrorCode.IO_EXCEPTION, e.toString());
        }
        return null;
    }

    private static CliError runHttpFile(HttpFileOptions httpFileOptions) {
        ReqInEditParser parser = new ReqInEditParser();
        JsEnvironment env = JsEnvironment.loadEnvironment(httpFileOptions.httpFile, httpFileOptions.envName);

        try (RawHttpCliClient httpClient = RawHttpCliClient.create(
                httpFileOptions.logRequest, httpFileOptions.printResponseMode,
                httpFileOptions.ignoreTlsCert, httpFileOptions.cookieJar)) {
            List entries = parser.parse(httpFileOptions.httpFile);
            try (ReqInEditUnit unit = new ReqInEditUnit(env, HTTP, new RedirectingRawHttpClient<>(httpClient))) {
                boolean allTestsPass = unit.run(entries);
                if (!allTestsPass) {
                    return new CliError(ErrorCode.USER_TEST_FAILURE, "FAIL: There were test failures!");
                }
            }
        } catch (IOException e) {
            return new CliError(ErrorCode.IO_EXCEPTION, e.toString());
        }
        return null;
    }

    private static CliError serve(ServerOptions options) {
        if (options.dir.isFile()) {
            return new CliError(ErrorCode.BAD_USAGE, "Error: not a directory - " + options.dir);
        }

        System.out.println("Serving directory " + options.dir.getAbsolutePath() + " on port " + options.port);

        if (!options.dir.exists()) {
            System.err.println("Warning: The provided directory does not exist: " + options.dir + "\n" +
                    "The server will not serve any files until the directory exists.");
        }

        RequestLogger requestLogger = options.logRequests
                ? new AsyncSysoutRequestLogger()
                : new NoopRequestLogger();
        RawHttpServer server = new TcpRawHttpServer(new CliServerOptions(options.port, requestLogger));
        Optional mediaTypesFile = options.getMediaTypesFile();
        if (mediaTypesFile.isPresent()) {
            Properties mediaTypeProperties = new Properties();
            try {
                mediaTypeProperties.load(new FileReader(mediaTypesFile.get()));
            } catch (IOException e) {
                return new CliError(ErrorCode.IO_EXCEPTION, "Could not read media-types file: " + e.getMessage());
            }
            server.start(new CliServerRouter(options.dir, options.rootPath, mediaTypeProperties));
        } else {
            server.start(new CliServerRouter(options.dir, options.rootPath));
        }
        return null;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy