package uws.service.request;
/*
* This file is part of UWSLibrary.
*
* UWSLibrary is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* UWSLibrary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with UWSLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2014 - Astronomisches Rechen Institut (ARI)
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import uws.UWSException;
import uws.service.UWS;
import uws.service.file.UWSFileManager;
/**
* <p>This parser merely copies the whole HTTP request content inside a file.
* It names this file: "JDL" (Job Description Language).</p>
*
* <p>
* The created file is stored in the temporary upload directory ({@link UWSFileManager#TMP_UPLOAD_DIR} ; this attribute can be modified if needed).
* This directory is supposed to be emptied regularly in case it is forgotten at any moment by the UWS service implementation to delete unused request files.
* </p>
*
* <p>
* The size of the JDL is limited by the static attribute {@link #SIZE_LIMIT} before the creation of the file.
* Its default value is: {@link #DEFAULT_SIZE_LIMIT}={@value #DEFAULT_SIZE_LIMIT} bytes.
* </p>
*
* @author Grégory Mantelet (ARI)
* @version 4.1 (11/2014)
* @since 4.1
*/
public class NoEncodingParser implements RequestParser {
/** Default maximum allowed size for an HTTP request content: 2 MiB. */
public static final int DEFAULT_SIZE_LIMIT = 2 * 1024 * 1024;
/** <p>Maximum allowed size for an HTTP request content. Over this limit, an exception is thrown and the request is aborted.</p>
* <p><i>Note:
* The default value is {@link #DEFAULT_SIZE_LIMIT} (= {@value #DEFAULT_SIZE_LIMIT} MiB).
* </i></p>
* <p><i>Note:
* This limit is expressed in bytes and can not be negative.
* Its smallest possible value is 0. If the set value is though negative,
* it will be ignored and {@link #DEFAULT_SIZE_LIMIT} will be used instead.
* </i></p> */
public static int SIZE_LIMIT = DEFAULT_SIZE_LIMIT;
/** File manager to use to create {@link UploadFile} instances.
* It is required by this new object to execute open, move and delete operations whenever it could be asked. */
protected final UWSFileManager fileManager;
/**
* Build the request parser.
*
* @param fileManager A file manager. <b>MUST NOT be NULL</b>
*/
public NoEncodingParser(final UWSFileManager fileManager){
if (fileManager == null)
throw new NullPointerException("Missing file manager => can not create a SingleDataParser!");
this.fileManager = fileManager;
}
@Override
public Map<String,Object> parse(final HttpServletRequest request) throws UWSException{
// Check the request size:
if (request.getContentLength() <= 0)
return new HashMap<String,Object>();
else if (request.getContentLength() > (SIZE_LIMIT < 0 ? DEFAULT_SIZE_LIMIT : SIZE_LIMIT))
throw new UWSException("JDL too big (>" + SIZE_LIMIT + " bytes) => Request rejected! You should see with the service administrator to extend this limit.");
// Build the parameter name:
String paramName;
if (request.getMethod() != null && request.getMethod().equalsIgnoreCase("put")){
paramName = request.getRequestURI();
if (paramName.lastIndexOf('/') + 1 > 0)
paramName = paramName.substring(paramName.lastIndexOf('/') + 1);
}else
paramName = "JDL";
// Build the file by copy of the whole request body:
Object reqID = request.getAttribute(UWS.REQ_ATTRIBUTE_ID);
if (reqID == null || !(reqID instanceof String))
reqID = (new Date()).getTime();
File f = new File(UWSFileManager.TMP_UPLOAD_DIR, "REQUESTBODY_" + reqID);
OutputStream output = null;
InputStream input = null;
long totalLength = 0;
try{
output = new BufferedOutputStream(new FileOutputStream(f));
input = new BufferedInputStream(request.getInputStream());
byte[] buffer = new byte[2049];
int len = input.read(buffer);
if (len <= 0){
output.close();
f.delete();
HashMap<String,Object> params = new HashMap<String,Object>(1);
params.put(paramName, "");
return params;
}else if (len <= 2048 && request.getMethod() != null && request.getMethod().equalsIgnoreCase("put") && request.getContentType() != null && request.getContentType().toLowerCase().startsWith("text/plain")){
output.close();
f.delete();
HashMap<String,Object> params = new HashMap<String,Object>(1);
params.put(paramName, new String(buffer, 0, len));
return params;
}else{
do{
output.write(buffer, 0, len);
totalLength += len;
}while((len = input.read(buffer)) > 0);
output.flush();
}
}catch(IOException ioe){
throw new UWSException(UWSException.INTERNAL_SERVER_ERROR, ioe, "Internal error => Impossible to get the JDL from the HTTP request!");
}finally{
if (input != null){
try{
input.close();
}catch(IOException ioe2){}
}
if (output != null){
try{
output.close();
}catch(IOException ioe2){}
}
}
// Build its description:
UploadFile lob = new UploadFile(paramName, f.toURI().toString(), fileManager);
lob.mimeType = request.getContentType();
lob.length = totalLength;
// Create the parameters map:
HashMap<String,Object> parameters = new HashMap<String,Object>();
parameters.put(paramName, lob);
return parameters;
}
}