📄 cmsrequesthttpservlet.java
字号:
// The real boundary is always preceeded by an extra "--"
boundary = "--" + boundary;
return boundary;
}
/**
* Extracts and returns the content type from a line, or null if the
* line was empty.
* @param line Line from input stream.
* @return Content type of the line.
* @throws IOException Throws an IOException if the line is malformatted.
*/
private String extractContentType(String line) throws IOException {
String contentType = null;
// Convert the line to a lowercase string
String origline = line;
line = origline.toLowerCase();
// Get the content type, if any
if (line.startsWith("content-type")) {
int start = line.indexOf(" ");
if (start == -1) {
throw new IOException("Content type corrupt: " + origline);
}
contentType = line.substring(start + 1);
} else {
if (line.length() != 0) {
// no content type, so should be empty
throw new IOException("Malformed line after disposition: " + origline);
}
}
return contentType;
}
/**
* Extracts and returns disposition info from a line, as a String array
* with elements: disposition, name, filename. Throws an IOException
* if the line is malformatted.
*
* @param line Line from input stream.
* @return Array of string containing disposition information.
* @throws IOException if the line is malformatted
*/
private String[] extractDispositionInfo(String line) throws IOException {
// Return the line's data as an array: disposition, name, filename
String[] retval = new String[3];
// Convert the line to a lowercase string without the ending \r\n
// Keep the original line for error messages and for variable names.
String origline = line;
line = origline.toLowerCase();
// Get the content disposition, should be "form-data"
int start = line.indexOf("content-disposition: ");
int end = line.indexOf(";");
if (start == -1 || end == -1) {
throw new IOException("Content disposition corrupt: " + origline);
}
String disposition = line.substring(start + 21, end);
if (!disposition.equals("form-data")) {
throw new IOException("Invalid content disposition: " + disposition);
}
// Get the field name
// start at last semicolon
start = line.indexOf("name=\"", end);
// skip name=\"
end = line.indexOf("\"", start + 7);
if (start == -1 || end == -1) {
throw new IOException("Content disposition corrupt: " + origline);
}
String name = origline.substring(start + 6, end);
// Get the filename, if given
String filename = null;
// start after name
start = line.indexOf("filename=\"", end + 2);
// skip filename=\"
end = line.indexOf("\"", start + 10);
// note the !=
if (start != -1 && end != -1) {
filename = origline.substring(start + 10, end);
// The filename may contain a full path. Cut to just the filename.
int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
if (slash > -1) {
filename = filename.substring(slash + 1); // past last slash
}
if (filename.equals("")) {
filename = "unknown"; // sanity check
}
}
// Translate the filename using the resource translator
filename = m_translator.translateResource(filename);
// Return a String array: disposition, name, filename
retval[0] = disposition;
retval[1] = name;
retval[2] = filename;
return retval;
}
/**
* A utility method that reads a single part of the multipart request
* that represents a file. Unlike the method name it does NOT saves the file to disk.
* The name is from the original O'Reilly implmentaton.
* <p>
* A subclass can override this method for a better optimized or
* differently behaved implementation.
*
* @param in The stream from which to read the file.
* @param boundary The boundary signifying the end of this part.
* @return the output
* @throws IOException If there's a problem reading or parsing the request.
*/
private byte[] readAndSaveFile(CmsMultipartInputStreamHandler in, String boundary) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(8 * 1024);
byte[] boundaryBytes = boundary.getBytes();
int[] lookaheadBuf = new int[boundary.length() + 3];
int[] newLineBuf = {
-1, -1
};
int matches = 0;
int matchingByte = new Byte(boundaryBytes[matches]).intValue();
/*
File parts of multipart request should not be read line by line.
Since some servlet environments touch and change the new line
character(s) when calling the ServletInputStream's <code>readLine</code>
this may cause problems with binary file uploads.
We decided to read this parts byte by byte here.
*/
int read = in.read();
while (read > -1) {
if (read == matchingByte) {
// read byte is matching the next byte of the boundary
// we should not write to the output stream here.
lookaheadBuf[matches] = read;
matches++;
if (matches == boundary.length()) {
// The end of the Boundary has been reached.
// Now snip the following line feed.
read = in.read();
if (newLineBuf[1] == read) {
// New line contains ONE single character.
// Write the last byte of the buffer to the output stream.
out.write(newLineBuf[0]);
} else {
// new line contains TWO characters, possibly "\r\n"
// The bytes in the buffer are not part of the file.
// We even have to read one more byte.
in.read();
}
break;
}
matchingByte = new Byte(boundaryBytes[matches]).intValue();
} else {
// read byte does not match the next byte of the boundary
// write the first buffer byte to the output stream
if (newLineBuf[0] != -1) {
out.write(newLineBuf[0]);
}
if (matches == 0) {
// this may be the most propably case.
newLineBuf[0] = newLineBuf[1];
} else {
// we have started to read the boundary.
// Unfortunately, this was NOT the real boundary.
// Fall back to normal read mode.
// write the complete buffer to the output stream
if (newLineBuf[1] != -1) {
out.write(newLineBuf[1]);
}
for (int i = 0; i < matches; i++) {
out.write(lookaheadBuf[i]);
}
// reset boundary matching counter
matches = 0;
matchingByte = new Byte(boundaryBytes[matches]).intValue();
// clear buffer
newLineBuf[0] = -1;
}
// put the last byte read into the buffer.
// it may be part of a line feed.
newLineBuf[1] = read;
}
read = in.read();
}
out.flush();
return out.toByteArray();
}
/**
* A utility method that reads an individual part. Dispatches to
* readParameter() and readAndSaveFile() to do the actual work.
* <p>
* The single files are stored in a hashtable (seperated in filename and contents)
* for later addition to a CmsFile Object
* <p> A subclass can override this method for a better optimized or
* differently behaved implementation.
*
* @param in The stream from which to read the part
* @param boundary The boundary separating parts
* @return A flag indicating whether this is the last part
* @throws IOException If there's a problem reading or parsing the
* request
*/
private boolean readNextPart(CmsMultipartInputStreamHandler in, String boundary) throws IOException {
// Read the first line, should look like this:
// content-disposition: form-data; name="field1"; filename="file1.txt"
String line = in.readLine();
if (line == null || line.equals("")) {
// No parts left, we're done
return true;
}
// Parse the content-disposition line
String[] dispInfo = extractDispositionInfo(line);
// String disposition = dispInfo[0];
String name = dispInfo[1];
String filename = dispInfo[2];
// Now onto the next line. This will either be empty
// or contain a Content-Type and then an empty line.
line = in.readLine();
if (line == null) {
// No parts left, we're done
return true;
}
// Get the content type, or null if none specified
String contentType = extractContentType(line);
if (contentType != null) {
// Eat the empty line
line = in.readLine();
if (line == null || line.length() > 0) { // line should be empty
line = in.readLine();
if (line == null || line.length() > 0) { // line should be empty
throw new IOException("Malformed line after content type: " + line);
}
}
} else {
// Assume a default content type
contentType = "application/octet-stream";
}
// Now, finally, we read the content (end after reading the boundary)
if (filename == null) {
// This is a parameter
String value = readParameter(in, boundary);
m_parameters.put(name, value);
} else {
m_filecounter++;
// stroe the filecontent
m_files.put(filename, readAndSaveFile(in, boundary));
// store the name of the file to the parameters
m_parameters.put(name, filename);
}
// there's more to read
return false;
}
/**
* A utility method that reads a single part of the multipart request
* that represents a parameter. A subclass can override this method
* for a better optimized or differently behaved implementation.
*
* @param in The stream from which to read the parameter information
* @param boundary The boundary signifying the end of this part
* @return The parameter value
* @throws IOException If there's a problem reading or parsing the
* request
*/
private String readParameter(CmsMultipartInputStreamHandler in, String boundary) throws IOException {
StringBuffer sbuf = new StringBuffer();
String line;
while ((line = in.readLine()) != null) {
if (line.startsWith(boundary)) {
break;
}
// add the \r\n in case there are many lines
sbuf.append(line + "\r\n");
}
if (sbuf.length() == 0) {
// nothing read
return null;
}
// cut off the last line's \r\n
sbuf.setLength(sbuf.length() - 2);
// no URL decoding needed
return sbuf.toString();
}
/**
* This method actually parses the request. A subclass
* can override this method for a better optimized or differently
* behaved implementation.
*
* @throws IOException If the uploaded content is larger than
* <tt>maxSize</tt> or there's a problem parsing the request.
*/
private void readRequest() throws IOException {
// Check the content type to make sure it's "multipart/form-data"
String type = m_req.getContentType();
if (type == null || !type.toLowerCase().startsWith("multipart/form-data")) {
throw new IOException(C_REQUEST_NOMULTIPART);
}
int length = m_req.getContentLength();
// Get the boundary string; it's included in the content type.
// Should look something like "------------------------12012133613061"
String boundary = extractBoundary(type);
if (boundary == null) {
throw new IOException(C_REQUEST_NOBOUNDARY);
}
// Construct the special input stream we'll read from
CmsMultipartInputStreamHandler in = new CmsMultipartInputStreamHandler(m_req.getInputStream(), length);
// Read the first line, should be the first boundary
String line = in.readLine();
if (line == null) {
throw new IOException(C_REQUEST_PROMATUREEND);
}
// Verify that the line is the boundary
if (!line.startsWith(boundary)) {
throw new IOException(C_REQUEST_NOBOUNDARY);
}
// Now that we're just beyond the first boundary, loop over each part
boolean done = false;
while (!done) {
done = readNextPart(in, boundary);
}
// Unfortunately some servlet environmets cannot handle multipart
// requests AND URL parameters at the same time, we have to manage
// the URL params ourself here. So try to read th URL parameters:
String queryString = m_req.getQueryString();
if (queryString != null) {
StringTokenizer st = new StringTokenizer(m_req.getQueryString(), "&");
while (st.hasMoreTokens()) {
// Loop through all parameters
String currToken = st.nextToken();
if (currToken != null && !"".equals(currToken)) {
// look for the "=" character to divide parameter name and value
int idx = currToken.indexOf("=");
if (idx > -1) {
String key = currToken.substring(0, idx);
String value = (idx < (currToken.length() - 1)) ? currToken.substring(idx + 1) : "";
m_parameters.put(key, value);
}
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -