Package fitnesse.http

Source Code of fitnesse.http.Request

// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.http;

import fitnesse.ContextConfigurator;
import fitnesse.util.Base64;
import util.StreamReader;

import java.io.*;
import java.net.URLDecoder;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Request {
  private static final Pattern requestLinePattern = Pattern
  .compile("(\\p{Upper}+?) ([^\\s]+)");
  private static final Pattern requestUriPattern = Pattern
  .compile("([^?]+)\\??(.*)");
  private static final Pattern queryStringPattern = Pattern
  .compile("([^=&]*)=?([^&]*)&?");
  private static final Pattern headerPattern = Pattern.compile("([^:]*): (.*)");
  private static final Pattern boundaryPattern = Pattern
  .compile("boundary=(.*)");
  private static final Pattern multipartHeaderPattern = Pattern
  .compile("([^ =]+)=\\\"([^\"]*)\\\"");

  private static final Collection<String> allowedMethods = buildAllowedMethodList();

  /** input key to suppress chunking. */
  public static final String NOCHUNK = "nochunk";

  protected StreamReader input;
  private String contextRoot = ContextConfigurator.DEFAULT_CONTEXT_ROOT;
  protected String requestURI;
  private String resource;
  protected String queryString;
  protected Map<String, Object> inputs = new HashMap<String, Object>();
  protected Map<String, Object> headers = new HashMap<String, Object>();
  protected String entityBody = "";
  protected String requestLine;
  protected String authorizationUsername;
  protected String authorizationPassword;
  private volatile boolean hasBeenParsed;
  private long bytesParsed = 0;

  public static Set<String> buildAllowedMethodList() {
    Set<String> methods = new HashSet<String>(20);
    methods.add("GET");
    methods.add("POST");
    return methods;
  }

  protected Request() {
  }

  public Request(InputStream input) {
    this.input = new StreamReader(new BufferedInputStream(input));
  }

  public void parse() throws HttpException {
    try {
      readAndParseRequestLine();
      headers = parseHeaders(input);
      parseEntityBody();
    } catch (IOException e) {
      throw new HttpException("Unable to process request: " + e.getMessage());
    }
    hasBeenParsed = true;
  }

  private void readAndParseRequestLine() throws IOException, HttpException {
    requestLine = input.readLine();
    Matcher match = requestLinePattern.matcher(requestLine);
    checkRequestLine(match);
    requestURI = match.group(2);
    parseRequestUri(requestURI);
  }

  private Map<String, Object> parseHeaders(StreamReader reader) throws IOException {
    HashMap<String, Object> headers = new HashMap<String, Object>();
    String line = reader.readLine();
    while (!"".equals(line)) {
      Matcher match = headerPattern.matcher(line);
      if (match.find()) {
        String key = match.group(1);
        String value = match.group(2);
        headers.put(key.toLowerCase(), value);
      }
      line = reader.readLine();
    }
    return headers;
  }

  private void parseEntityBody() throws IOException {
    if (hasHeader("Content-Length")) {
      String contentType = (String) getHeader("Content-Type");
      if (contentType != null && contentType.startsWith("multipart/form-data")) {
        Matcher match = boundaryPattern.matcher(contentType);
        match.find();
        parseMultiPartContent(match.group(1));
      } else {
        entityBody = input.read(getContentLength());
        parseQueryString(entityBody);
      }
    }
  }

  public int getContentLength() {
    return Integer.parseInt((String) getHeader("Content-Length"));
  }

  private void parseMultiPartContent(String boundary) throws IOException {
    boundary = "--" + boundary;

    int numberOfBytesToRead = getContentLength();
    accumulateBytesReadAndReset();
    input.readUpTo(boundary);
    while (numberOfBytesToRead - input.numberOfBytesConsumed() > 10) {
      input.readLine();
      Map<String, Object> headers = parseHeaders(input);
      String contentDisposition = (String) headers.get("content-disposition");
      Matcher matcher = multipartHeaderPattern.matcher(contentDisposition);
      while (matcher.find())
        headers.put(matcher.group(1), matcher.group(2));

      String name = (String) headers.get("name");
      Object value;
      if (headers.containsKey("filename"))
        value = createUploadedFile(headers, input, boundary);
      else
        value = input.readUpTo("\r\n" + boundary);

      inputs.put(name, value);
    }
  }

  private void accumulateBytesReadAndReset() {
    bytesParsed += input.numberOfBytesConsumed();
    input.resetNumberOfBytesConsumed();
  }

  private Object createUploadedFile(Map<String, Object> headers,
      StreamReader reader, String boundary) throws IOException {
    String filename = (String) headers.get("filename");
    String contentType = (String) headers.get("content-type");
    File tempFile = File.createTempFile("FitNesse", ".uploadedFile");
    OutputStream output = null;
    try {
      output = new BufferedOutputStream(new FileOutputStream(tempFile));
      reader.copyBytesUpTo("\r\n" + boundary, output);
      return new UploadedFile(filename, contentType, tempFile);
    } finally {
      if (output != null)
        output.close();
    }
  }

  private void checkRequestLine(Matcher match) throws HttpException {
    if (!match.find())
      throw new HttpException(
      "The request string is malformed and can not be parsed");
    if (!allowedMethods.contains(match.group(1)))
      throw new HttpException("The " + match.group(1)
          + " method is not currently supported");
  }

  public void parseRequestUri(String requestUri) {
    Matcher match = requestUriPattern.matcher(requestUri);
    match.find();
    resource = stripContextRoot(match.group(1));
    queryString = match.group(2);
    parseQueryString(queryString);
  }

  protected void parseQueryString(String queryString) {
    Matcher match = queryStringPattern.matcher(queryString);
    while (match.find()) {
      String key = match.group(1);
      String value = decodeContent(match.group(2));
      addUniqueInputString(key, value);
    }
  }

  private void addUniqueInputString(String key, String value) {
    Object existingItem = inputs.put(key, value);
    if (itemExistAndMismatches(existingItem, value)) {
      inputs.put(key, concatenateItems((String)existingItem, value));
    }
  }

  private String concatenateItems(String existingItem, String value) {
    StringBuffer buffer = new StringBuffer();
    buffer.append(existingItem);
    buffer.append(',');
    buffer.append(value);
    return buffer.toString();
  }

  private boolean itemExistAndMismatches(Object existingItem, String value) {
    return existingItem instanceof String && !value.equals(existingItem);
  }

  public String getRequestLine() {
    return requestLine;
  }

  public String getRequestUri() {
    return requestURI;
  }

  public String getResource() {
    return resource;
  }

  public void setResource(String resource) {
    this.resource = resource;
  }

  public String getQueryString() {
    return queryString;
  }

  public boolean hasInput(String key) {
    return inputs.containsKey(key);
  }

  public Object getInput(String key) {
    return inputs.get(key);
  }

  public Map<String,Object> getMap(){
    return inputs;
  }

  public boolean hasHeader(String key) {
    return headers.containsKey(key.toLowerCase());
  }

  public Object getHeader(String key) {
    return headers.get(key.toLowerCase());
  }

  public String getBody() {
    return entityBody;
  }

  private String stripContextRoot(String url) {
    if (contextRoot.equals(url + "/")) {
      return "";
    }
    if (url.startsWith(contextRoot)) {
      return url.substring(contextRoot.length());
    }
    return url;
  }

  public String toString() {
    StringBuffer buffer = new StringBuffer();
    buffer.append("--- Request Start ---\n");
    buffer.append("Request URI:  ").append(requestURI).append('\n');
    buffer.append("Resource:     ").append(resource).append('\n');
    buffer.append("Query String: ").append(queryString).append('\n');
    buffer.append("Hearders: (").append(headers.size()).append(")\n");
    addMap(headers, buffer);
    buffer.append("Form Inputs: (").append(inputs.size()).append(")\n");
    addMap(inputs, buffer);
    buffer.append("Entity Body: \n");
    buffer.append(entityBody).append('\n');
    buffer.append("--- End Request ---\n");

    return buffer.toString();
  }

  private void addMap(Map<String, Object> map, StringBuffer buffer) {
    if (map.isEmpty()) {
      buffer.append("\tempty");
    }
    for (Entry<String, Object> entry: map.entrySet()) {
      String value = entry.getValue() == null ? null : escape(entry.getValue().toString());
      buffer.append("\t" + escape(entry.getKey()) + " \t-->\t " + value + "\n");
    }
  }

  private String escape(String foo) {
    return foo.replaceAll("[\n\r]+", "|");
  }

  public static String decodeContent(String content) {
    try {
      return URLDecoder.decode(content, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      return "URLDecoder Error";
    }
  }

  public boolean hasBeenParsed() {
    return hasBeenParsed;
  }

  public String getUserpass(String headerValue) {
    String encodedUserpass = headerValue.substring(6);
    try {
      return Base64.decode(encodedUserpass);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  public void getCredentials() {
    if (authorizationUsername != null)
      return;
    if (hasHeader("Authorization")) {
      String authHeader = getHeader("Authorization").toString();
      String userpass = getUserpass(authHeader);
      String[] values = userpass.split(":");
      if (values.length == 2) {
        authorizationUsername = values[0];
        authorizationPassword = values[1];
      }
    }
  }

  public String getAuthorizationUsername() {
    return authorizationUsername;
  }

  public String getAuthorizationPassword() {
    return authorizationPassword;
  }

  public long numberOfBytesParsed() {
    return bytesParsed + input.numberOfBytesConsumed();
  }

  public void setCredentials(String username, String password) {
    authorizationUsername = username;
    authorizationPassword = password;
  }

  public void setContextRoot(String contextRoot) {
    this.contextRoot = contextRoot;
  }
}
TOP

Related Classes of fitnesse.http.Request

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.