001package io.prometheus.metrics.exporter.servlet.javax;
002
003import io.prometheus.metrics.exporter.common.PrometheusHttpExchange;
004import io.prometheus.metrics.exporter.common.PrometheusHttpRequest;
005import io.prometheus.metrics.exporter.common.PrometheusHttpResponse;
006
007import javax.servlet.http.HttpServletRequest;
008import javax.servlet.http.HttpServletResponse;
009import java.io.IOException;
010import java.io.OutputStream;
011import java.util.Enumeration;
012
013/**
014 * This class is an adapter for HTTP exchanges, implementing the PrometheusHttpExchange interface.
015 * It wraps HttpServletRequest and HttpServletResponse objects into Request and Response inner classes.
016 */
017public class HttpExchangeAdapter implements PrometheusHttpExchange {
018
019    private final Request request;
020    private final Response response;
021
022    /**
023     * Constructs a new HttpExchangeAdapter with the given HttpServletRequest and HttpServletResponse.
024     *
025     * @param request  the HttpServletRequest to be adapted
026     * @param response the HttpServletResponse to be adapted
027     */
028    public HttpExchangeAdapter(HttpServletRequest request, HttpServletResponse response) {
029        this.request = new Request(request);
030        this.response = new Response(response);
031    }
032
033    /**
034     * Returns the adapted HttpServletRequest.
035     *
036     * @return the adapted HttpServletRequest
037     */
038    @Override
039    public PrometheusHttpRequest getRequest() {
040        return request;
041    }
042
043    /**
044     * Returns the adapted HttpServletResponse.
045     *
046     * @return the adapted HttpServletResponse
047     */
048    @Override
049    public PrometheusHttpResponse getResponse() {
050        return response;
051    }
052
053    @Override
054    public void handleException(IOException e) throws IOException {
055        throw e; // leave exception handling to the servlet container
056    }
057
058    @Override
059    public void handleException(RuntimeException e) {
060        throw e; // leave exception handling to the servlet container
061    }
062
063    @Override
064    public void close() {
065        // nothing to do for Servlets.
066    }
067
068    /**
069     * This inner class adapts a HttpServletRequest to a PrometheusHttpRequest.
070     */
071    public static class Request implements PrometheusHttpRequest {
072
073        private final HttpServletRequest request;
074
075        /**
076         * Constructs a new Request with the given HttpServletRequest.
077         *
078         * @param request the HttpServletRequest to be adapted
079         */
080        public Request(HttpServletRequest request) {
081            this.request = request;
082        }
083
084        @Override
085        public String getQueryString() {
086            return request.getQueryString();
087        }
088
089
090        @Override
091        public Enumeration<String> getHeaders(String name) {
092            return request.getHeaders(name);
093        }
094
095
096        @Override
097        public String getMethod() {
098            return request.getMethod();
099        }
100
101
102        @Override
103        public String getRequestPath() {
104            StringBuilder uri = new StringBuilder();
105            String contextPath = request.getContextPath();
106            if (contextPath.startsWith("/")) {
107                uri.append(contextPath);
108            }
109            String servletPath = request.getServletPath();
110            if (servletPath.startsWith("/")) {
111                uri.append(servletPath);
112            }
113            String pathInfo = request.getPathInfo();
114            if (pathInfo != null) {
115                uri.append(pathInfo);
116            }
117            return uri.toString();
118        }
119    }
120
121    /**
122     * This inner class adapts a HttpServletResponse to a PrometheusHttpResponse.
123     */
124    public static class Response implements PrometheusHttpResponse {
125
126        private final HttpServletResponse response;
127
128        /**
129         * Constructs a new Response with the given HttpServletResponse.
130         *
131         * @param response the HttpServletResponse to be adapted
132         */
133        public Response(HttpServletResponse response) {
134            this.response = response;
135        }
136
137
138        @Override
139        public void setHeader(String name, String value) {
140            response.setHeader(name, value);
141        }
142
143
144        @Override
145        public OutputStream sendHeadersAndGetBody(int statusCode, int contentLength) throws IOException {
146            if (response.getHeader("Content-Length") == null && contentLength > 0) {
147                response.setContentLength(contentLength);
148            }
149            response.setStatus(statusCode);
150            return response.getOutputStream();
151        }
152    }
153}