package com.github.mkopylec.charon.core.http;

import java.io.IOException;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import com.github.mkopylec.charon.exceptions.CharonException;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;

import static java.util.Collections.list;
import static org.apache.commons.io.IOUtils.toByteArray;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.springframework.http.HttpMethod.resolve;

public class RequestDataExtractor {

    public byte[] extractBody(HttpServletRequest request) {
        try {
            return toByteArray(request.getInputStream());
        } catch (IOException e) {
            throw new CharonException("Error extracting body of HTTP request with URI: " + extractUri(request), e);
        }
    }

    public HttpHeaders extractHttpHeaders(HttpServletRequest request) {
        HttpHeaders headers = new HttpHeaders();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            List<String> value = list(request.getHeaders(name));
            headers.put(name, value);
        }
        return headers;
    }

    public HttpMethod extractHttpMethod(HttpServletRequest request) {
        return resolve(request.getMethod());
    }

    public String extractUri(HttpServletRequest request) {
        return request.getRequestURI() + getQuery(request);
    }

    protected String getQuery(HttpServletRequest request) {
        return request.getQueryString() == null ? EMPTY : "?" + request.getQueryString();
    }
}

@@ -59,72 +59,410 @@
 .io.
-IOException;%0Aimport java.util.Enumeration;%0Aimport java.util.List
+ByteArrayInputStream;%0Aimport java.io.ByteArrayOutputStream;%0Aimport java.io.IOException;%0Aimport java.io.InputStream;%0Aimport java.io.OutputStreamWriter;%0Aimport java.io.Writer;%0Aimport java.net.URLEncoder;%0Aimport java.nio.charset.Charset;%0Aimport java.nio.charset.StandardCharsets;%0Aimport java.util.Arrays;%0Aimport java.util.Enumeration;%0Aimport java.util.Iterator;%0Aimport java.util.List;%0Aimport java.util.Map
 ;%0A%0Ai
@@ -914,16 +914,182 @@
 ctor %7B%0A%0A
+    protected static final String FORM_CONTENT_TYPE = %22application/x-www-form-urlencoded%22;%0A    protected static final Charset FORM_CHARSET = StandardCharsets.UTF_8;%0A%0A
     publ
@@ -1189,31 +1189,23 @@
 ray(
-request.getInputStream(
+getBody(request
 ));%0A
@@ -2105,32 +2105,32 @@
 uest request) %7B%0A
-
         return r
@@ -2208,11 +2208,2143 @@
 );%0A    %7D
+%0A%0A    private InputStream getBody(HttpServletRequest request) throws IOException %7B%0A        if (isFormPost(request)) %7B%0A            return getBodyFromServletRequestParameters(request);%0A        %7D else %7B%0A            return request.getInputStream();%0A        %7D%0A    %7D%0A%0A    private static boolean isFormPost(HttpServletRequest request) %7B%0A        String contentType = request.getContentType();%0A        return (contentType != null && contentType.contains(FORM_CONTENT_TYPE) &&%0A                HttpMethod.POST.matches(request.getMethod()));%0A    %7D%0A%0A    /**%0A     * Use %7B@link javax.servlet.ServletRequest#getParameterMap()%7D to reconstruct the%0A     * body of a form 'POST' providing a predictable outcome as opposed to reading%0A     * from the body, which can fail if any other code has used the ServletRequest%0A     * to access a parameter, thus causing the input stream to be %22consumed%22.%0A     */%0A    private static InputStream getBodyFromServletRequestParameters(HttpServletRequest request) throws IOException %7B%0A        ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);%0A        Writer writer = new OutputStreamWriter(bos, FORM_CHARSET);%0A%0A        Map%3CString, String%5B%5D%3E form = request.getParameterMap();%0A        for (Iterator%3CString%3E nameIterator = form.keySet().iterator(); nameIterator.hasNext();) %7B%0A            String name = nameIterator.next();%0A            List%3CString%3E values = Arrays.asList(form.get(name));%0A            for (Iterator%3CString%3E valueIterator = values.iterator(); valueIterator.hasNext();) %7B%0A                String value = valueIterator.next();%0A                writer.write(URLEncoder.encode(name, FORM_CHARSET.name()));%0A                if (value != null) %7B%0A                    writer.write('=');%0A                    writer.write(URLEncoder.encode(value, FORM_CHARSET.name()));%0A                    if (valueIterator.hasNext()) %7B%0A                        writer.write('&');%0A                    %7D%0A                %7D%0A            %7D%0A            if (nameIterator.hasNext()) %7B%0A                writer.append('&');%0A            %7D%0A        %7D%0A        writer.flush();%0A%0A        return new ByteArrayInputStream(bos.toByteArray());%0A    %7D
 %0A%7D%0A

Fix for getting form body from HttpServletRequest