Port http multipart package. See #709
This commit is contained in:
parent
4e3258973f
commit
36ac52a4bd
@ -227,14 +227,9 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
if (b == null) {
|
if (b == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b.readable()) {
|
if (b.readable()) {
|
||||||
addComponent(cIndex ++, b);
|
// Always add b to the end of the component list because we are appending buffers
|
||||||
int size = components.size();
|
addComponent(components.size(), b);
|
||||||
if (cIndex > size) {
|
|
||||||
// was consolidated, so adjust index. #707
|
|
||||||
cIndex = size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
57
buffer/src/test/java/io/netty/buffer/ConsolidationTest.java
Normal file
57
buffer/src/test/java/io/netty/buffer/ConsolidationTest.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer;
|
||||||
|
|
||||||
|
import static io.netty.buffer.Unpooled.wrappedBuffer;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests buffer consolidation
|
||||||
|
*/
|
||||||
|
public class ConsolidationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldWrapInSequence() {
|
||||||
|
ByteBuf currentBuffer = wrappedBuffer(wrappedBuffer("a".getBytes()), wrappedBuffer("=".getBytes()));
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("1".getBytes()), wrappedBuffer("&".getBytes()));
|
||||||
|
|
||||||
|
String s = new String(currentBuffer.copy().array());
|
||||||
|
assertEquals("a=1&", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldConsolidationInSequence() {
|
||||||
|
ByteBuf currentBuffer = wrappedBuffer(wrappedBuffer("a".getBytes()), wrappedBuffer("=".getBytes()));
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("1".getBytes()), wrappedBuffer("&".getBytes()));
|
||||||
|
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("b".getBytes()), wrappedBuffer("=".getBytes()));
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("2".getBytes()), wrappedBuffer("&".getBytes()));
|
||||||
|
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("c".getBytes()), wrappedBuffer("=".getBytes()));
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("3".getBytes()), wrappedBuffer("&".getBytes()));
|
||||||
|
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("d".getBytes()), wrappedBuffer("=".getBytes()));
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("4".getBytes()), wrappedBuffer("&".getBytes()));
|
||||||
|
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("e".getBytes()), wrappedBuffer("=".getBytes()));
|
||||||
|
currentBuffer = wrappedBuffer(currentBuffer, wrappedBuffer("5".getBytes()), wrappedBuffer("&".getBytes()));
|
||||||
|
|
||||||
|
String s = new String(currentBuffer.copy().array());
|
||||||
|
assertEquals("a=1&b=2&c=3&d=4&e=5&", s);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import static io.netty.buffer.Unpooled.*;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.handler.codec.http.HttpConstants;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Disk HttpData implementation
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDiskHttpData extends AbstractHttpData {
|
||||||
|
|
||||||
|
protected File file;
|
||||||
|
private boolean isRenamed;
|
||||||
|
private FileChannel fileChannel;
|
||||||
|
|
||||||
|
public AbstractDiskHttpData(String name, Charset charset, long size) {
|
||||||
|
super(name, charset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the real DiskFilename (basename)
|
||||||
|
*/
|
||||||
|
protected abstract String getDiskFilename();
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the default prefix
|
||||||
|
*/
|
||||||
|
protected abstract String getPrefix();
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the default base Directory
|
||||||
|
*/
|
||||||
|
protected abstract String getBaseDirectory();
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the default postfix
|
||||||
|
*/
|
||||||
|
protected abstract String getPostfix();
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return True if the file should be deleted on Exit by default
|
||||||
|
*/
|
||||||
|
protected abstract boolean deleteOnExit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return a new Temp File from getDiskFilename(), default prefix, postfix and baseDirectory
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private File tempFile() throws IOException {
|
||||||
|
String newpostfix = null;
|
||||||
|
String diskFilename = getDiskFilename();
|
||||||
|
if (diskFilename != null) {
|
||||||
|
newpostfix = "_" + diskFilename;
|
||||||
|
} else {
|
||||||
|
newpostfix = getPostfix();
|
||||||
|
}
|
||||||
|
File tmpFile;
|
||||||
|
if (getBaseDirectory() == null) {
|
||||||
|
// create a temporary file
|
||||||
|
tmpFile = File.createTempFile(getPrefix(), newpostfix);
|
||||||
|
} else {
|
||||||
|
tmpFile = File.createTempFile(getPrefix(), newpostfix, new File(
|
||||||
|
getBaseDirectory()));
|
||||||
|
}
|
||||||
|
if (deleteOnExit()) {
|
||||||
|
tmpFile.deleteOnExit();
|
||||||
|
}
|
||||||
|
return tmpFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(ByteBuf buffer) throws IOException {
|
||||||
|
if (buffer == null) {
|
||||||
|
throw new NullPointerException("buffer");
|
||||||
|
}
|
||||||
|
size = buffer.readableBytes();
|
||||||
|
if (definedSize > 0 && definedSize < size) {
|
||||||
|
throw new IOException("Out of size: " + size + " > " + definedSize);
|
||||||
|
}
|
||||||
|
if (file == null) {
|
||||||
|
file = tempFile();
|
||||||
|
}
|
||||||
|
if (buffer.readableBytes() == 0) {
|
||||||
|
// empty file
|
||||||
|
file.createNewFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
FileChannel localfileChannel = outputStream.getChannel();
|
||||||
|
ByteBuffer byteBuffer = buffer.nioBuffer();
|
||||||
|
int written = 0;
|
||||||
|
while (written < size) {
|
||||||
|
written += localfileChannel.write(byteBuffer);
|
||||||
|
}
|
||||||
|
buffer.readerIndex(buffer.readerIndex() + written);
|
||||||
|
localfileChannel.force(false);
|
||||||
|
localfileChannel.close();
|
||||||
|
outputStream.close();
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addContent(ByteBuf buffer, boolean last)
|
||||||
|
throws IOException {
|
||||||
|
if (buffer != null) {
|
||||||
|
int localsize = buffer.readableBytes();
|
||||||
|
if (definedSize > 0 && definedSize < size + localsize) {
|
||||||
|
throw new IOException("Out of size: " + (size + localsize) +
|
||||||
|
" > " + definedSize);
|
||||||
|
}
|
||||||
|
ByteBuffer byteBuffer = buffer.hasNioBuffer() ? buffer.nioBuffer() : buffer.copy().nioBuffer();
|
||||||
|
int written = 0;
|
||||||
|
if (file == null) {
|
||||||
|
file = tempFile();
|
||||||
|
}
|
||||||
|
if (fileChannel == null) {
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
fileChannel = outputStream.getChannel();
|
||||||
|
}
|
||||||
|
while (written < localsize) {
|
||||||
|
written += fileChannel.write(byteBuffer);
|
||||||
|
}
|
||||||
|
size += localsize;
|
||||||
|
buffer.readerIndex(buffer.readerIndex() + written);
|
||||||
|
}
|
||||||
|
if (last) {
|
||||||
|
if (file == null) {
|
||||||
|
file = tempFile();
|
||||||
|
}
|
||||||
|
if (fileChannel == null) {
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
fileChannel = outputStream.getChannel();
|
||||||
|
}
|
||||||
|
fileChannel.force(false);
|
||||||
|
fileChannel.close();
|
||||||
|
fileChannel = null;
|
||||||
|
completed = true;
|
||||||
|
} else {
|
||||||
|
if (buffer == null) {
|
||||||
|
throw new NullPointerException("buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(File file) throws IOException {
|
||||||
|
if (this.file != null) {
|
||||||
|
delete();
|
||||||
|
}
|
||||||
|
this.file = file;
|
||||||
|
size = file.length();
|
||||||
|
isRenamed = true;
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(InputStream inputStream) throws IOException {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new NullPointerException("inputStream");
|
||||||
|
}
|
||||||
|
if (file != null) {
|
||||||
|
delete();
|
||||||
|
}
|
||||||
|
file = tempFile();
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
FileChannel localfileChannel = outputStream.getChannel();
|
||||||
|
byte[] bytes = new byte[4096 * 4];
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||||
|
int read = inputStream.read(bytes);
|
||||||
|
int written = 0;
|
||||||
|
while (read > 0) {
|
||||||
|
byteBuffer.position(read).flip();
|
||||||
|
written += localfileChannel.write(byteBuffer);
|
||||||
|
read = inputStream.read(bytes);
|
||||||
|
}
|
||||||
|
localfileChannel.force(false);
|
||||||
|
localfileChannel.close();
|
||||||
|
size = written;
|
||||||
|
if (definedSize > 0 && definedSize < size) {
|
||||||
|
file.delete();
|
||||||
|
file = null;
|
||||||
|
throw new IOException("Out of size: " + size + " > " + definedSize);
|
||||||
|
}
|
||||||
|
isRenamed = true;
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
if (! isRenamed) {
|
||||||
|
if (file != null) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] get() throws IOException {
|
||||||
|
if (file == null) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
return readFrom(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getByteBuf() throws IOException {
|
||||||
|
if (file == null) {
|
||||||
|
return EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
byte[] array = readFrom(file);
|
||||||
|
return wrappedBuffer(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getChunk(int length) throws IOException {
|
||||||
|
if (file == null || length == 0) {
|
||||||
|
return EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
if (fileChannel == null) {
|
||||||
|
FileInputStream inputStream = new FileInputStream(file);
|
||||||
|
fileChannel = inputStream.getChannel();
|
||||||
|
}
|
||||||
|
int read = 0;
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocate(length);
|
||||||
|
while (read < length) {
|
||||||
|
int readnow = fileChannel.read(byteBuffer);
|
||||||
|
if (readnow == -1) {
|
||||||
|
fileChannel.close();
|
||||||
|
fileChannel = null;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
read += readnow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (read == 0) {
|
||||||
|
return EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
byteBuffer.flip();
|
||||||
|
ByteBuf buffer = wrappedBuffer(byteBuffer);
|
||||||
|
buffer.readerIndex(0);
|
||||||
|
buffer.writerIndex(read);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() throws IOException {
|
||||||
|
return getString(HttpConstants.DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(Charset encoding) throws IOException {
|
||||||
|
if (file == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (encoding == null) {
|
||||||
|
byte[] array = readFrom(file);
|
||||||
|
return new String(array, HttpConstants.DEFAULT_CHARSET.name());
|
||||||
|
}
|
||||||
|
byte[] array = readFrom(file);
|
||||||
|
return new String(array, encoding.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInMemory() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameTo(File dest) throws IOException {
|
||||||
|
if (dest == null) {
|
||||||
|
throw new NullPointerException("dest");
|
||||||
|
}
|
||||||
|
if (!file.renameTo(dest)) {
|
||||||
|
// must copy
|
||||||
|
FileInputStream inputStream = new FileInputStream(file);
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(dest);
|
||||||
|
FileChannel in = inputStream.getChannel();
|
||||||
|
FileChannel out = outputStream.getChannel();
|
||||||
|
int chunkSize = 8196;
|
||||||
|
long position = 0;
|
||||||
|
while (position < size) {
|
||||||
|
if (chunkSize < size - position) {
|
||||||
|
chunkSize = (int) (size - position);
|
||||||
|
}
|
||||||
|
position += in.transferTo(position, chunkSize , out);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
out.close();
|
||||||
|
if (position == size) {
|
||||||
|
file.delete();
|
||||||
|
file = dest;
|
||||||
|
isRenamed = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
dest.delete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file = dest;
|
||||||
|
isRenamed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function
|
||||||
|
* @param src
|
||||||
|
* @return the array of bytes
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private static byte[] readFrom(File src) throws IOException {
|
||||||
|
long srcsize = src.length();
|
||||||
|
if (srcsize > Integer.MAX_VALUE) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"File too big to be loaded in memory");
|
||||||
|
}
|
||||||
|
FileInputStream inputStream = new FileInputStream(src);
|
||||||
|
FileChannel fileChannel = inputStream.getChannel();
|
||||||
|
byte[] array = new byte[(int) srcsize];
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
|
||||||
|
int read = 0;
|
||||||
|
while (read < srcsize) {
|
||||||
|
read += fileChannel.read(byteBuffer);
|
||||||
|
}
|
||||||
|
fileChannel.close();
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() throws IOException {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract HttpData implementation
|
||||||
|
*/
|
||||||
|
public abstract class AbstractHttpData implements HttpData {
|
||||||
|
|
||||||
|
protected final String name;
|
||||||
|
protected long definedSize;
|
||||||
|
protected long size;
|
||||||
|
protected Charset charset = HttpConstants.DEFAULT_CHARSET;
|
||||||
|
protected boolean completed;
|
||||||
|
|
||||||
|
public AbstractHttpData(String name, Charset charset, long size) {
|
||||||
|
if (name == null) {
|
||||||
|
throw new NullPointerException("name");
|
||||||
|
}
|
||||||
|
name = name.trim();
|
||||||
|
if (name.length() == 0) {
|
||||||
|
throw new IllegalArgumentException("empty name");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < name.length(); i ++) {
|
||||||
|
char c = name.charAt(i);
|
||||||
|
if (c > 127) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"name contains non-ascii character: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check prohibited characters.
|
||||||
|
switch (c) {
|
||||||
|
case '=':
|
||||||
|
case ',':
|
||||||
|
case ';':
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case '\f':
|
||||||
|
case 0x0b: // Vertical tab
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"name contains one of the following prohibited characters: " +
|
||||||
|
"=,; \\t\\r\\n\\v\\f: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.name = name;
|
||||||
|
if (charset != null) {
|
||||||
|
setCharset(charset);
|
||||||
|
}
|
||||||
|
definedSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Charset getCharset() {
|
||||||
|
return charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharset(Charset charset) {
|
||||||
|
if (charset == null) {
|
||||||
|
throw new NullPointerException("charset");
|
||||||
|
}
|
||||||
|
this.charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long length() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
|
||||||
|
import static io.netty.buffer.Unpooled.buffer;
|
||||||
|
import static io.netty.buffer.Unpooled.wrappedBuffer;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.handler.codec.http.HttpConstants;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Memory HttpData implementation
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMemoryHttpData extends AbstractHttpData {
|
||||||
|
|
||||||
|
private ByteBuf byteBuf;
|
||||||
|
private int chunkPosition;
|
||||||
|
protected boolean isRenamed;
|
||||||
|
|
||||||
|
public AbstractMemoryHttpData(String name, Charset charset, long size) {
|
||||||
|
super(name, charset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(ByteBuf buffer) throws IOException {
|
||||||
|
if (buffer == null) {
|
||||||
|
throw new NullPointerException("buffer");
|
||||||
|
}
|
||||||
|
long localsize = buffer.readableBytes();
|
||||||
|
if (definedSize > 0 && definedSize < localsize) {
|
||||||
|
throw new IOException("Out of size: " + localsize + " > " +
|
||||||
|
definedSize);
|
||||||
|
}
|
||||||
|
byteBuf = buffer;
|
||||||
|
size = localsize;
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(InputStream inputStream) throws IOException {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new NullPointerException("inputStream");
|
||||||
|
}
|
||||||
|
ByteBuf buffer = buffer();
|
||||||
|
byte[] bytes = new byte[4096 * 4];
|
||||||
|
int read = inputStream.read(bytes);
|
||||||
|
int written = 0;
|
||||||
|
while (read > 0) {
|
||||||
|
buffer.writeBytes(bytes);
|
||||||
|
written += read;
|
||||||
|
read = inputStream.read(bytes);
|
||||||
|
}
|
||||||
|
size = written;
|
||||||
|
if (definedSize > 0 && definedSize < size) {
|
||||||
|
throw new IOException("Out of size: " + size + " > " + definedSize);
|
||||||
|
}
|
||||||
|
byteBuf = buffer;
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addContent(ByteBuf buffer, boolean last)
|
||||||
|
throws IOException {
|
||||||
|
if (buffer != null) {
|
||||||
|
long localsize = buffer.readableBytes();
|
||||||
|
if (definedSize > 0 && definedSize < size + localsize) {
|
||||||
|
throw new IOException("Out of size: " + (size + localsize) +
|
||||||
|
" > " + definedSize);
|
||||||
|
}
|
||||||
|
size += localsize;
|
||||||
|
if (byteBuf == null) {
|
||||||
|
byteBuf = buffer;
|
||||||
|
} else {
|
||||||
|
byteBuf = wrappedBuffer(byteBuf, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (last) {
|
||||||
|
completed = true;
|
||||||
|
} else {
|
||||||
|
if (buffer == null) {
|
||||||
|
throw new NullPointerException("buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(File file) throws IOException {
|
||||||
|
if (file == null) {
|
||||||
|
throw new NullPointerException("file");
|
||||||
|
}
|
||||||
|
long newsize = file.length();
|
||||||
|
if (newsize > Integer.MAX_VALUE) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"File too big to be loaded in memory");
|
||||||
|
}
|
||||||
|
FileInputStream inputStream = new FileInputStream(file);
|
||||||
|
FileChannel fileChannel = inputStream.getChannel();
|
||||||
|
byte[] array = new byte[(int) newsize];
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
|
||||||
|
int read = 0;
|
||||||
|
while (read < newsize) {
|
||||||
|
read += fileChannel.read(byteBuffer);
|
||||||
|
}
|
||||||
|
fileChannel.close();
|
||||||
|
inputStream.close();
|
||||||
|
byteBuffer.flip();
|
||||||
|
byteBuf = wrappedBuffer(byteBuffer);
|
||||||
|
size = newsize;
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] get() {
|
||||||
|
if (byteBuf == null) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
byte[] array = new byte[byteBuf.readableBytes()];
|
||||||
|
byteBuf.getBytes(byteBuf.readerIndex(), array);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
|
return getString(HttpConstants.DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(Charset encoding) {
|
||||||
|
if (byteBuf == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (encoding == null) {
|
||||||
|
return getString(HttpConstants.DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
return byteBuf.toString(encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to go from a In Memory FileUpload
|
||||||
|
* to a Disk (or another implementation) FileUpload
|
||||||
|
* @return the attached ByteBuf containing the actual bytes
|
||||||
|
*/
|
||||||
|
public ByteBuf getByteBuf() {
|
||||||
|
return byteBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getChunk(int length) throws IOException {
|
||||||
|
if (byteBuf == null || length == 0 || byteBuf.readableBytes() == 0) {
|
||||||
|
chunkPosition = 0;
|
||||||
|
return EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
int sizeLeft = byteBuf.readableBytes() - chunkPosition;
|
||||||
|
if (sizeLeft == 0) {
|
||||||
|
chunkPosition = 0;
|
||||||
|
return EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
int sliceLength = length;
|
||||||
|
if (sizeLeft < length) {
|
||||||
|
sliceLength = sizeLeft;
|
||||||
|
}
|
||||||
|
ByteBuf chunk = byteBuf.slice(chunkPosition, sliceLength);
|
||||||
|
chunkPosition += sliceLength;
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInMemory() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameTo(File dest) throws IOException {
|
||||||
|
if (dest == null) {
|
||||||
|
throw new NullPointerException("dest");
|
||||||
|
}
|
||||||
|
if (byteBuf == null) {
|
||||||
|
// empty file
|
||||||
|
dest.createNewFile();
|
||||||
|
isRenamed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int length = byteBuf.readableBytes();
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(dest);
|
||||||
|
FileChannel fileChannel = outputStream.getChannel();
|
||||||
|
ByteBuffer byteBuffer = byteBuf.nioBuffer();
|
||||||
|
int written = 0;
|
||||||
|
while (written < length) {
|
||||||
|
written += fileChannel.write(byteBuffer);
|
||||||
|
}
|
||||||
|
fileChannel.force(false);
|
||||||
|
fileChannel.close();
|
||||||
|
outputStream.close();
|
||||||
|
isRenamed = true;
|
||||||
|
return written == length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() throws IOException {
|
||||||
|
throw new IOException("Not represented by a file");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute interface
|
||||||
|
*/
|
||||||
|
public interface Attribute extends HttpData {
|
||||||
|
/**
|
||||||
|
* Returns the value of this HttpData.
|
||||||
|
*/
|
||||||
|
String getValue() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of this HttpData.
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
void setValue(String value) throws IOException;
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public final class CaseIgnoringComparator implements Comparator<String>, Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4582133183775373862L;
|
||||||
|
|
||||||
|
public static final CaseIgnoringComparator INSTANCE = new CaseIgnoringComparator();
|
||||||
|
|
||||||
|
private CaseIgnoringComparator() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(String o1, String o2) {
|
||||||
|
return o1.compareToIgnoreCase(o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("static-method")
|
||||||
|
private Object readResolve() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default factory giving Attribute and FileUpload according to constructor
|
||||||
|
*
|
||||||
|
* Attribute and FileUpload could be :<br>
|
||||||
|
* - MemoryAttribute, DiskAttribute or MixedAttribute<br>
|
||||||
|
* - MemoryFileUpload, DiskFileUpload or MixedFileUpload<br>
|
||||||
|
* according to the constructor.
|
||||||
|
*/
|
||||||
|
public class DefaultHttpDataFactory implements HttpDataFactory {
|
||||||
|
/**
|
||||||
|
* Proposed default MINSIZE as 16 KB.
|
||||||
|
*/
|
||||||
|
public static long MINSIZE = 0x4000;
|
||||||
|
|
||||||
|
private final boolean useDisk;
|
||||||
|
|
||||||
|
private final boolean checkSize;
|
||||||
|
|
||||||
|
private long minSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep all HttpDatas until cleanAllHttpDatas() is called.
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMap<HttpRequest, List<HttpData>> requestFileDeleteMap =
|
||||||
|
new ConcurrentHashMap<HttpRequest, List<HttpData>>();
|
||||||
|
/**
|
||||||
|
* HttpData will be in memory if less than default size (16KB).
|
||||||
|
* The type will be Mixed.
|
||||||
|
*/
|
||||||
|
public DefaultHttpDataFactory() {
|
||||||
|
useDisk = false;
|
||||||
|
checkSize = true;
|
||||||
|
minSize = MINSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpData will be always on Disk if useDisk is True, else always in Memory if False
|
||||||
|
* @param useDisk
|
||||||
|
*/
|
||||||
|
public DefaultHttpDataFactory(boolean useDisk) {
|
||||||
|
this.useDisk = useDisk;
|
||||||
|
checkSize = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpData will be on Disk if the size of the file is greater than minSize, else it
|
||||||
|
* will be in memory. The type will be Mixed.
|
||||||
|
* @param minSize
|
||||||
|
*/
|
||||||
|
public DefaultHttpDataFactory(long minSize) {
|
||||||
|
useDisk = false;
|
||||||
|
checkSize = true;
|
||||||
|
this.minSize = minSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @return the associated list of Files for the request
|
||||||
|
*/
|
||||||
|
private List<HttpData> getList(HttpRequest request) {
|
||||||
|
List<HttpData> list = requestFileDeleteMap.get(request);
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<HttpData>();
|
||||||
|
requestFileDeleteMap.put(request, list);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attribute createAttribute(HttpRequest request, String name) {
|
||||||
|
if (useDisk) {
|
||||||
|
Attribute attribute = new DiskAttribute(name);
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.add(attribute);
|
||||||
|
return attribute;
|
||||||
|
} else if (checkSize) {
|
||||||
|
Attribute attribute = new MixedAttribute(name, minSize);
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.add(attribute);
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
return new MemoryAttribute(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attribute createAttribute(HttpRequest request, String name, String value) {
|
||||||
|
if (useDisk) {
|
||||||
|
Attribute attribute;
|
||||||
|
try {
|
||||||
|
attribute = new DiskAttribute(name, value);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// revert to Mixed mode
|
||||||
|
attribute = new MixedAttribute(name, value, minSize);
|
||||||
|
}
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.add(attribute);
|
||||||
|
return attribute;
|
||||||
|
} else if (checkSize) {
|
||||||
|
Attribute attribute = new MixedAttribute(name, value, minSize);
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.add(attribute);
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new MemoryAttribute(name, value);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileUpload createFileUpload(HttpRequest request, String name, String filename,
|
||||||
|
String contentType, String contentTransferEncoding, Charset charset,
|
||||||
|
long size) {
|
||||||
|
if (useDisk) {
|
||||||
|
FileUpload fileUpload = new DiskFileUpload(name, filename, contentType,
|
||||||
|
contentTransferEncoding, charset, size);
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.add(fileUpload);
|
||||||
|
return fileUpload;
|
||||||
|
} else if (checkSize) {
|
||||||
|
FileUpload fileUpload = new MixedFileUpload(name, filename, contentType,
|
||||||
|
contentTransferEncoding, charset, size, minSize);
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.add(fileUpload);
|
||||||
|
return fileUpload;
|
||||||
|
}
|
||||||
|
return new MemoryFileUpload(name, filename, contentType,
|
||||||
|
contentTransferEncoding, charset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data) {
|
||||||
|
if (data instanceof HttpData) {
|
||||||
|
List<HttpData> fileToDelete = getList(request);
|
||||||
|
fileToDelete.remove(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanRequestHttpDatas(HttpRequest request) {
|
||||||
|
List<HttpData> fileToDelete = requestFileDeleteMap.remove(request);
|
||||||
|
if (fileToDelete != null) {
|
||||||
|
for (HttpData data: fileToDelete) {
|
||||||
|
data.delete();
|
||||||
|
}
|
||||||
|
fileToDelete.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanAllHttpDatas() {
|
||||||
|
for (HttpRequest request : requestFileDeleteMap.keySet()) {
|
||||||
|
List<HttpData> fileToDelete = requestFileDeleteMap.get(request);
|
||||||
|
if (fileToDelete != null) {
|
||||||
|
for (HttpData data: fileToDelete) {
|
||||||
|
data.delete();
|
||||||
|
}
|
||||||
|
fileToDelete.clear();
|
||||||
|
}
|
||||||
|
requestFileDeleteMap.remove(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.handler.codec.http.HttpConstants;
|
||||||
|
import static io.netty.buffer.Unpooled.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disk implementation of Attributes
|
||||||
|
*/
|
||||||
|
public class DiskAttribute extends AbstractDiskHttpData implements Attribute {
|
||||||
|
public static String baseDirectory;
|
||||||
|
|
||||||
|
public static boolean deleteOnExitTemporaryFile = true;
|
||||||
|
|
||||||
|
public static String prefix = "Attr_";
|
||||||
|
|
||||||
|
public static String postfix = ".att";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used for huge Attribute
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public DiskAttribute(String name) {
|
||||||
|
super(name, HttpConstants.DEFAULT_CHARSET, 0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param value
|
||||||
|
* @throws NullPointerException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public DiskAttribute(String name, String value) throws IOException {
|
||||||
|
super(name, HttpConstants.DEFAULT_CHARSET, 0); // Attribute have no default size
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return HttpDataType.Attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() throws IOException {
|
||||||
|
byte [] bytes = get();
|
||||||
|
return new String(bytes, charset.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException("value");
|
||||||
|
}
|
||||||
|
byte [] bytes = value.getBytes(charset.name());
|
||||||
|
ByteBuf buffer = wrappedBuffer(bytes);
|
||||||
|
if (definedSize > 0) {
|
||||||
|
definedSize = buffer.readableBytes();
|
||||||
|
}
|
||||||
|
setContent(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addContent(ByteBuf buffer, boolean last) throws IOException {
|
||||||
|
int localsize = buffer.readableBytes();
|
||||||
|
if (definedSize > 0 && definedSize < size + localsize) {
|
||||||
|
definedSize = size + localsize;
|
||||||
|
}
|
||||||
|
super.addContent(buffer, last);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getName().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Attribute attribute = (Attribute) o;
|
||||||
|
return getName().equalsIgnoreCase(attribute.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData arg0) {
|
||||||
|
if (!(arg0 instanceof Attribute)) {
|
||||||
|
throw new ClassCastException("Cannot compare " + getHttpDataType() +
|
||||||
|
" with " + arg0.getHttpDataType());
|
||||||
|
}
|
||||||
|
return compareTo((Attribute) arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(Attribute o) {
|
||||||
|
return getName().compareToIgnoreCase(o.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
try {
|
||||||
|
return getName() + "=" + getValue();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return getName() + "=IoException";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean deleteOnExit() {
|
||||||
|
return deleteOnExitTemporaryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getBaseDirectory() {
|
||||||
|
return baseDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDiskFilename() {
|
||||||
|
return getName() + postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPostfix() {
|
||||||
|
return postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disk FileUpload implementation that stores file into real files
|
||||||
|
*/
|
||||||
|
public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
|
||||||
|
public static String baseDirectory;
|
||||||
|
|
||||||
|
public static boolean deleteOnExitTemporaryFile = true;
|
||||||
|
|
||||||
|
public static String prefix = "FUp_";
|
||||||
|
|
||||||
|
public static String postfix = ".tmp";
|
||||||
|
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
private String contentType;
|
||||||
|
|
||||||
|
private String contentTransferEncoding;
|
||||||
|
|
||||||
|
public DiskFileUpload(String name, String filename, String contentType,
|
||||||
|
String contentTransferEncoding, Charset charset, long size) {
|
||||||
|
super(name, charset, size);
|
||||||
|
setFilename(filename);
|
||||||
|
setContentType(contentType);
|
||||||
|
setContentTransferEncoding(contentTransferEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return HttpDataType.FileUpload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
if (filename == null) {
|
||||||
|
throw new NullPointerException("filename");
|
||||||
|
}
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getName().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Attribute attribute = (Attribute) o;
|
||||||
|
return getName().equalsIgnoreCase(attribute.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData arg0) {
|
||||||
|
if (!(arg0 instanceof FileUpload)) {
|
||||||
|
throw new ClassCastException("Cannot compare " + getHttpDataType() +
|
||||||
|
" with " + arg0.getHttpDataType());
|
||||||
|
}
|
||||||
|
return compareTo((FileUpload) arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(FileUpload o) {
|
||||||
|
int v;
|
||||||
|
v = getName().compareToIgnoreCase(o.getName());
|
||||||
|
if (v != 0) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
// TODO should we compare size ?
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
if (contentType == null) {
|
||||||
|
throw new NullPointerException("contentType");
|
||||||
|
}
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentTransferEncoding() {
|
||||||
|
return contentTransferEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentTransferEncoding(String contentTransferEncoding) {
|
||||||
|
this.contentTransferEncoding = contentTransferEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
|
||||||
|
HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + getName() +
|
||||||
|
"\"; " + HttpPostBodyUtil.FILENAME + "=\"" + filename + "\"\r\n" +
|
||||||
|
HttpHeaders.Names.CONTENT_TYPE + ": " + contentType +
|
||||||
|
(charset != null? "; " + HttpHeaders.Values.CHARSET + "=" + charset + "\r\n" : "\r\n") +
|
||||||
|
HttpHeaders.Names.CONTENT_LENGTH + ": " + length() + "\r\n" +
|
||||||
|
"Completed: " + isCompleted() +
|
||||||
|
"\r\nIsInMemory: " + isInMemory() + "\r\nRealFile: " +
|
||||||
|
file.getAbsolutePath() + " DefaultDeleteAfter: " +
|
||||||
|
deleteOnExitTemporaryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean deleteOnExit() {
|
||||||
|
return deleteOnExitTemporaryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getBaseDirectory() {
|
||||||
|
return baseDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDiskFilename() {
|
||||||
|
File file = new File(filename);
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPostfix() {
|
||||||
|
return postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileUpload interface that could be in memory, on temporary file or any other implementations.
|
||||||
|
*
|
||||||
|
* Most methods are inspired from java.io.File API.
|
||||||
|
*/
|
||||||
|
public interface FileUpload extends HttpData {
|
||||||
|
/**
|
||||||
|
* Returns the original filename in the client's filesystem,
|
||||||
|
* as provided by the browser (or other client software).
|
||||||
|
* @return the original filename
|
||||||
|
*/
|
||||||
|
String getFilename();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the original filename
|
||||||
|
* @param filename
|
||||||
|
*/
|
||||||
|
void setFilename(String filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Content Type passed by the browser if defined
|
||||||
|
* @param contentType Content Type to set - must be not null
|
||||||
|
*/
|
||||||
|
void setContentType(String contentType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content type passed by the browser or null if not defined.
|
||||||
|
* @return the content type passed by the browser or null if not defined.
|
||||||
|
*/
|
||||||
|
String getContentType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Content-Transfer-Encoding type from String as 7bit, 8bit or binary
|
||||||
|
* @param contentTransferEncoding
|
||||||
|
*/
|
||||||
|
void setContentTransferEncoding(String contentTransferEncoding);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Content-Transfer-Encoding
|
||||||
|
* @return the Content-Transfer-Encoding
|
||||||
|
*/
|
||||||
|
String getContentTransferEncoding();
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extended interface for InterfaceHttpData
|
||||||
|
*/
|
||||||
|
public interface HttpData extends InterfaceHttpData {
|
||||||
|
/**
|
||||||
|
* Set the content from the ChannelBuffer (erase any previous data)
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* must be not null
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
void setContent(ByteBuf buffer) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the content from the ChannelBuffer
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* must be not null except if last is set to False
|
||||||
|
* @param last
|
||||||
|
* True of the buffer is the last one
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
void addContent(ByteBuf buffer, boolean last) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the content from the file (erase any previous data)
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* must be not null
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
void setContent(File file) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the content from the inputStream (erase any previous data)
|
||||||
|
*
|
||||||
|
* @param inputStream
|
||||||
|
* must be not null
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
void setContent(InputStream inputStream) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return True if the InterfaceHttpData is completed (all data are stored)
|
||||||
|
*/
|
||||||
|
boolean isCompleted();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size in byte of the InterfaceHttpData
|
||||||
|
*
|
||||||
|
* @return the size of the InterfaceHttpData
|
||||||
|
*/
|
||||||
|
long length();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the underlying storage for a file item, including deleting any
|
||||||
|
* associated temporary disk file.
|
||||||
|
*/
|
||||||
|
void delete();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of the file item as an array of bytes.
|
||||||
|
*
|
||||||
|
* @return the contents of the file item as an array of bytes.
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
byte[] get() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of the file item as a ByteBuf
|
||||||
|
*
|
||||||
|
* @return the content of the file item as a ByteBuf
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
ByteBuf getByteBuf() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a ChannelBuffer for the content from the current position with at
|
||||||
|
* most length read bytes, increasing the current position of the Bytes
|
||||||
|
* read. Once it arrives at the end, it returns an EMPTY_BUFFER and it
|
||||||
|
* resets the current position to 0.
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* @return a ChannelBuffer for the content from the current position or an
|
||||||
|
* EMPTY_BUFFER if there is no more data to return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
ByteBuf getChunk(int length) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of the file item as a String, using the default
|
||||||
|
* character encoding.
|
||||||
|
*
|
||||||
|
* @return the contents of the file item as a String, using the default
|
||||||
|
* character encoding.
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
String getString() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of the file item as a String, using the specified
|
||||||
|
* charset.
|
||||||
|
*
|
||||||
|
* @param encoding
|
||||||
|
* the charset to use
|
||||||
|
* @return the contents of the file item as a String, using the specified
|
||||||
|
* charset.
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
String getString(Charset encoding) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Charset passed by the browser if defined
|
||||||
|
*
|
||||||
|
* @param charset
|
||||||
|
* Charset to set - must be not null
|
||||||
|
*/
|
||||||
|
void setCharset(Charset charset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Charset passed by the browser or null if not defined.
|
||||||
|
*
|
||||||
|
* @return the Charset passed by the browser or null if not defined.
|
||||||
|
*/
|
||||||
|
Charset getCharset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method to write an uploaded item to disk. If a previous one
|
||||||
|
* exists, it will be deleted. Once this method is called, if successful,
|
||||||
|
* the new file will be out of the cleaner of the factory that creates the
|
||||||
|
* original InterfaceHttpData object.
|
||||||
|
*
|
||||||
|
* @param dest
|
||||||
|
* destination file - must be not null
|
||||||
|
* @return True if the write is successful
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
boolean renameTo(File dest) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a hint as to whether or not the file contents will be read from
|
||||||
|
* memory.
|
||||||
|
*
|
||||||
|
* @return True if the file contents is in memory.
|
||||||
|
*/
|
||||||
|
boolean isInMemory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the associated File if this data is represented in a file
|
||||||
|
* @exception IOException
|
||||||
|
* if this data is not represented by a file
|
||||||
|
*/
|
||||||
|
File getFile() throws IOException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to enable creation of InterfaceHttpData objects
|
||||||
|
*/
|
||||||
|
public interface HttpDataFactory {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request associated request
|
||||||
|
* @param name
|
||||||
|
* @return a new Attribute with no value
|
||||||
|
* @throws NullPointerException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
*/
|
||||||
|
Attribute createAttribute(HttpRequest request, String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request associated request
|
||||||
|
* @param name
|
||||||
|
* @param value
|
||||||
|
* @return a new Attribute
|
||||||
|
* @throws NullPointerException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
*/
|
||||||
|
Attribute createAttribute(HttpRequest request, String name, String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request associated request
|
||||||
|
* @param name
|
||||||
|
* @param filename
|
||||||
|
* @param contentType
|
||||||
|
* @param charset
|
||||||
|
* @param size the size of the Uploaded file
|
||||||
|
* @return a new FileUpload
|
||||||
|
*/
|
||||||
|
FileUpload createFileUpload(HttpRequest request, String name, String filename,
|
||||||
|
String contentType, String contentTransferEncoding, Charset charset,
|
||||||
|
long size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given InterfaceHttpData from clean list (will not delete the file, except if the file
|
||||||
|
* is still a temporary one as setup at construction)
|
||||||
|
* @param request associated request
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all InterfaceHttpData from virtual File storage from clean list for the request
|
||||||
|
*
|
||||||
|
* @param request associated request
|
||||||
|
*/
|
||||||
|
void cleanRequestHttpDatas(HttpRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all InterfaceHttpData from virtual File storage from clean list for all requests
|
||||||
|
*/
|
||||||
|
void cleanAllHttpDatas();
|
||||||
|
}
|
@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared Static object between HttpMessageDecoder, HttpPostRequestDecoder and HttpPostRequestEncoder
|
||||||
|
*/
|
||||||
|
final class HttpPostBodyUtil {
|
||||||
|
|
||||||
|
public static int chunkSize = 8096;
|
||||||
|
/**
|
||||||
|
* HTTP content disposition header name.
|
||||||
|
*/
|
||||||
|
public static final String CONTENT_DISPOSITION = "Content-Disposition";
|
||||||
|
|
||||||
|
public static final String NAME = "name";
|
||||||
|
|
||||||
|
public static final String FILENAME = "filename";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content-disposition value for form data.
|
||||||
|
*/
|
||||||
|
public static final String FORM_DATA = "form-data";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content-disposition value for file attachment.
|
||||||
|
*/
|
||||||
|
public static final String ATTACHMENT = "attachment";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content-disposition value for file attachment.
|
||||||
|
*/
|
||||||
|
public static final String FILE = "file";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP content type body attribute for multiple uploads.
|
||||||
|
*/
|
||||||
|
public static final String MULTIPART_MIXED = "multipart/mixed";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charset for 8BIT
|
||||||
|
*/
|
||||||
|
public static final Charset ISO_8859_1 = CharsetUtil.ISO_8859_1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charset for 7BIT
|
||||||
|
*/
|
||||||
|
public static final Charset US_ASCII = CharsetUtil.US_ASCII;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Content-Type in binary form
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_BINARY_CONTENT_TYPE = "application/octet-stream";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Content-Type in Text form
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_TEXT_CONTENT_TYPE = "text/plain";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed mechanism for multipart
|
||||||
|
* mechanism := "7bit"
|
||||||
|
/ "8bit"
|
||||||
|
/ "binary"
|
||||||
|
Not allowed: "quoted-printable"
|
||||||
|
/ "base64"
|
||||||
|
*/
|
||||||
|
public enum TransferEncodingMechanism {
|
||||||
|
/**
|
||||||
|
* Default encoding
|
||||||
|
*/
|
||||||
|
BIT7("7bit"),
|
||||||
|
/**
|
||||||
|
* Short lines but not in ASCII - no encoding
|
||||||
|
*/
|
||||||
|
BIT8("8bit"),
|
||||||
|
/**
|
||||||
|
* Could be long text not in ASCII - no encoding
|
||||||
|
*/
|
||||||
|
BINARY("binary");
|
||||||
|
|
||||||
|
public String value;
|
||||||
|
|
||||||
|
TransferEncodingMechanism(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferEncodingMechanism() {
|
||||||
|
value = name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpPostBodyUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception when NO Backend Array is found
|
||||||
|
*/
|
||||||
|
static class SeekAheadNoBackArrayException extends Exception {
|
||||||
|
private static final long serialVersionUID = -630418804938699495L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class intends to decrease the CPU in seeking ahead some bytes in
|
||||||
|
* HttpPostRequestDecoder
|
||||||
|
*/
|
||||||
|
static class SeekAheadOptimize {
|
||||||
|
byte[] bytes;
|
||||||
|
int readerIndex;
|
||||||
|
int pos;
|
||||||
|
int origPos;
|
||||||
|
int limit;
|
||||||
|
ByteBuf buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param buffer
|
||||||
|
*/
|
||||||
|
SeekAheadOptimize(ByteBuf buffer) throws SeekAheadNoBackArrayException {
|
||||||
|
if (!buffer.hasArray()) {
|
||||||
|
throw new SeekAheadNoBackArrayException();
|
||||||
|
}
|
||||||
|
this.buffer = buffer;
|
||||||
|
bytes = buffer.array();
|
||||||
|
readerIndex = buffer.readerIndex();
|
||||||
|
origPos = pos = buffer.arrayOffset() + readerIndex;
|
||||||
|
limit = buffer.arrayOffset() + buffer.writerIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param minus this value will be used as (currentPos - minus) to set
|
||||||
|
* the current readerIndex in the buffer.
|
||||||
|
*/
|
||||||
|
void setReadPosition(int minus) {
|
||||||
|
pos -= minus;
|
||||||
|
readerIndex = getReadPosition(pos);
|
||||||
|
buffer.readerIndex(readerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param index raw index of the array (pos in general)
|
||||||
|
* @return the value equivalent of raw index to be used in readerIndex(value)
|
||||||
|
*/
|
||||||
|
int getReadPosition(int index) {
|
||||||
|
return index - origPos + readerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
buffer = null;
|
||||||
|
bytes = null;
|
||||||
|
limit = 0;
|
||||||
|
pos = 0;
|
||||||
|
readerIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first non whitespace
|
||||||
|
* @param sb
|
||||||
|
* @param offset
|
||||||
|
* @return the rank of the first non whitespace
|
||||||
|
*/
|
||||||
|
static int findNonWhitespace(String sb, int offset) {
|
||||||
|
int result;
|
||||||
|
for (result = offset; result < sb.length(); result ++) {
|
||||||
|
if (!Character.isWhitespace(sb.charAt(result))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first whitespace
|
||||||
|
* @param sb
|
||||||
|
* @param offset
|
||||||
|
* @return the rank of the first whitespace
|
||||||
|
*/
|
||||||
|
static int findWhitespace(String sb, int offset) {
|
||||||
|
int result;
|
||||||
|
for (result = offset; result < sb.length(); result ++) {
|
||||||
|
if (Character.isWhitespace(sb.charAt(result))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the end of String
|
||||||
|
* @param sb
|
||||||
|
* @return the rank of the end of string
|
||||||
|
*/
|
||||||
|
static int findEndOfString(String sb) {
|
||||||
|
int result;
|
||||||
|
for (result = sb.length(); result > 0; result --) {
|
||||||
|
if (!Character.isWhitespace(sb.charAt(result - 1))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for all Objects that could be encoded/decoded using HttpPostRequestEncoder/Decoder
|
||||||
|
*/
|
||||||
|
public interface InterfaceHttpData extends Comparable<InterfaceHttpData> {
|
||||||
|
enum HttpDataType {
|
||||||
|
Attribute, FileUpload, InternalAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of this InterfaceHttpData.
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return The HttpDataType
|
||||||
|
*/
|
||||||
|
HttpDataType getHttpDataType();
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Attribute is only for Encoder use to insert special command between object if needed
|
||||||
|
* (like Multipart Mixed mode)
|
||||||
|
*/
|
||||||
|
public class InternalAttribute implements InterfaceHttpData {
|
||||||
|
protected List<String> value = new ArrayList<String>();
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return HttpDataType.InternalAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addValue(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException("value");
|
||||||
|
}
|
||||||
|
this.value.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addValue(String value, int rank) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException("value");
|
||||||
|
}
|
||||||
|
this.value.add(rank, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value, int rank) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException("value");
|
||||||
|
}
|
||||||
|
this.value.set(rank, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getName().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Attribute attribute = (Attribute) o;
|
||||||
|
return getName().equalsIgnoreCase(attribute.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData arg0) {
|
||||||
|
if (!(arg0 instanceof InternalAttribute)) {
|
||||||
|
throw new ClassCastException("Cannot compare " + getHttpDataType() +
|
||||||
|
" with " + arg0.getHttpDataType());
|
||||||
|
}
|
||||||
|
return compareTo((InternalAttribute) arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InternalAttribute o) {
|
||||||
|
return getName().compareToIgnoreCase(o.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
int size = 0;
|
||||||
|
for (String elt : value) {
|
||||||
|
size += elt.length();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (String elt : value) {
|
||||||
|
result.append(elt);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return "InternalAttribute";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.handler.codec.http.HttpConstants;
|
||||||
|
import static io.netty.buffer.Unpooled.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory implementation of Attributes
|
||||||
|
*/
|
||||||
|
public class MemoryAttribute extends AbstractMemoryHttpData implements Attribute {
|
||||||
|
|
||||||
|
public MemoryAttribute(String name) {
|
||||||
|
super(name, HttpConstants.DEFAULT_CHARSET, 0);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param value
|
||||||
|
* @throws NullPointerException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public MemoryAttribute(String name, String value) throws IOException {
|
||||||
|
super(name, HttpConstants.DEFAULT_CHARSET, 0); // Attribute have no default size
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return HttpDataType.Attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return getByteBuf().toString(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException("value");
|
||||||
|
}
|
||||||
|
byte [] bytes = value.getBytes(charset.name());
|
||||||
|
ByteBuf buffer = wrappedBuffer(bytes);
|
||||||
|
if (definedSize > 0) {
|
||||||
|
definedSize = buffer.readableBytes();
|
||||||
|
}
|
||||||
|
setContent(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addContent(ByteBuf buffer, boolean last) throws IOException {
|
||||||
|
int localsize = buffer.readableBytes();
|
||||||
|
if (definedSize > 0 && definedSize < size + localsize) {
|
||||||
|
definedSize = size + localsize;
|
||||||
|
}
|
||||||
|
super.addContent(buffer, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getName().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Attribute attribute = (Attribute) o;
|
||||||
|
return getName().equalsIgnoreCase(attribute.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData arg0) {
|
||||||
|
if (!(arg0 instanceof Attribute)) {
|
||||||
|
throw new ClassCastException("Cannot compare " + getHttpDataType() +
|
||||||
|
" with " + arg0.getHttpDataType());
|
||||||
|
}
|
||||||
|
return compareTo((Attribute) arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(Attribute o) {
|
||||||
|
return getName().compareToIgnoreCase(o.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName() + "=" + getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default FileUpload implementation that stores file into memory.<br><br>
|
||||||
|
*
|
||||||
|
* Warning: be aware of the memory limitation.
|
||||||
|
*/
|
||||||
|
public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUpload {
|
||||||
|
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
private String contentType;
|
||||||
|
|
||||||
|
private String contentTransferEncoding;
|
||||||
|
|
||||||
|
public MemoryFileUpload(String name, String filename, String contentType,
|
||||||
|
String contentTransferEncoding, Charset charset, long size) {
|
||||||
|
super(name, charset, size);
|
||||||
|
setFilename(filename);
|
||||||
|
setContentType(contentType);
|
||||||
|
setContentTransferEncoding(contentTransferEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return HttpDataType.FileUpload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
if (filename == null) {
|
||||||
|
throw new NullPointerException("filename");
|
||||||
|
}
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getName().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Attribute attribute = (Attribute) o;
|
||||||
|
return getName().equalsIgnoreCase(attribute.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData arg0) {
|
||||||
|
if (!(arg0 instanceof FileUpload)) {
|
||||||
|
throw new ClassCastException("Cannot compare " + getHttpDataType() +
|
||||||
|
" with " + arg0.getHttpDataType());
|
||||||
|
}
|
||||||
|
return compareTo((FileUpload) arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(FileUpload o) {
|
||||||
|
int v;
|
||||||
|
v = getName().compareToIgnoreCase(o.getName());
|
||||||
|
if (v != 0) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
// TODO should we compare size for instance ?
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
if (contentType == null) {
|
||||||
|
throw new NullPointerException("contentType");
|
||||||
|
}
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentTransferEncoding() {
|
||||||
|
return contentTransferEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentTransferEncoding(String contentTransferEncoding) {
|
||||||
|
this.contentTransferEncoding = contentTransferEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
|
||||||
|
HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + getName() +
|
||||||
|
"\"; " + HttpPostBodyUtil.FILENAME + "=\"" + filename + "\"\r\n" +
|
||||||
|
HttpHeaders.Names.CONTENT_TYPE + ": " + contentType +
|
||||||
|
(charset != null? "; " + HttpHeaders.Values.CHARSET + "=" + charset + "\r\n" : "\r\n") +
|
||||||
|
HttpHeaders.Names.CONTENT_LENGTH + ": " + length() + "\r\n" +
|
||||||
|
"Completed: " + isCompleted() +
|
||||||
|
"\r\nIsInMemory: " + isInMemory();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mixed implementation using both in Memory and in File with a limit of size
|
||||||
|
*/
|
||||||
|
public class MixedAttribute implements Attribute {
|
||||||
|
private Attribute attribute;
|
||||||
|
|
||||||
|
private final long limitSize;
|
||||||
|
|
||||||
|
public MixedAttribute(String name, long limitSize) {
|
||||||
|
this.limitSize = limitSize;
|
||||||
|
attribute = new MemoryAttribute(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MixedAttribute(String name, String value, long limitSize) {
|
||||||
|
this.limitSize = limitSize;
|
||||||
|
if (value.length() > this.limitSize) {
|
||||||
|
try {
|
||||||
|
attribute = new DiskAttribute(name, value);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// revert to Memory mode
|
||||||
|
try {
|
||||||
|
attribute = new MemoryAttribute(name, value);
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
attribute = new MemoryAttribute(name, value);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addContent(ByteBuf buffer, boolean last) throws IOException {
|
||||||
|
if (attribute instanceof MemoryAttribute) {
|
||||||
|
if (attribute.length() + buffer.readableBytes() > limitSize) {
|
||||||
|
DiskAttribute diskAttribute = new DiskAttribute(attribute
|
||||||
|
.getName());
|
||||||
|
if (((MemoryAttribute) attribute).getByteBuf() != null) {
|
||||||
|
diskAttribute.addContent(((MemoryAttribute) attribute)
|
||||||
|
.getByteBuf(), false);
|
||||||
|
}
|
||||||
|
attribute = diskAttribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attribute.addContent(buffer, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
attribute.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] get() throws IOException {
|
||||||
|
return attribute.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getByteBuf() throws IOException {
|
||||||
|
return attribute.getByteBuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Charset getCharset() {
|
||||||
|
return attribute.getCharset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() throws IOException {
|
||||||
|
return attribute.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(Charset encoding) throws IOException {
|
||||||
|
return attribute.getString(encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return attribute.isCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInMemory() {
|
||||||
|
return attribute.isInMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long length() {
|
||||||
|
return attribute.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameTo(File dest) throws IOException {
|
||||||
|
return attribute.renameTo(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharset(Charset charset) {
|
||||||
|
attribute.setCharset(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(ByteBuf buffer) throws IOException {
|
||||||
|
if (buffer.readableBytes() > limitSize) {
|
||||||
|
if (attribute instanceof MemoryAttribute) {
|
||||||
|
// change to Disk
|
||||||
|
attribute = new DiskAttribute(attribute.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attribute.setContent(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(File file) throws IOException {
|
||||||
|
if (file.length() > limitSize) {
|
||||||
|
if (attribute instanceof MemoryAttribute) {
|
||||||
|
// change to Disk
|
||||||
|
attribute = new DiskAttribute(attribute.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attribute.setContent(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(InputStream inputStream) throws IOException {
|
||||||
|
if (attribute instanceof MemoryAttribute) {
|
||||||
|
// change to Disk even if we don't know the size
|
||||||
|
attribute = new DiskAttribute(attribute.getName());
|
||||||
|
}
|
||||||
|
attribute.setContent(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return attribute.getHttpDataType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return attribute.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData o) {
|
||||||
|
return attribute.compareTo(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Mixed: " + attribute.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() throws IOException {
|
||||||
|
return attribute.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) throws IOException {
|
||||||
|
attribute.setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getChunk(int length) throws IOException {
|
||||||
|
return attribute.getChunk(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() throws IOException {
|
||||||
|
return attribute.getFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mixed implementation using both in Memory and in File with a limit of size
|
||||||
|
*/
|
||||||
|
public class MixedFileUpload implements FileUpload {
|
||||||
|
private FileUpload fileUpload;
|
||||||
|
|
||||||
|
private final long limitSize;
|
||||||
|
|
||||||
|
private final long definedSize;
|
||||||
|
|
||||||
|
public MixedFileUpload(String name, String filename, String contentType,
|
||||||
|
String contentTransferEncoding, Charset charset, long size,
|
||||||
|
long limitSize) {
|
||||||
|
this.limitSize = limitSize;
|
||||||
|
if (size > this.limitSize) {
|
||||||
|
fileUpload = new DiskFileUpload(name, filename, contentType,
|
||||||
|
contentTransferEncoding, charset, size);
|
||||||
|
} else {
|
||||||
|
fileUpload = new MemoryFileUpload(name, filename, contentType,
|
||||||
|
contentTransferEncoding, charset, size);
|
||||||
|
}
|
||||||
|
definedSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addContent(ByteBuf buffer, boolean last)
|
||||||
|
throws IOException {
|
||||||
|
if (fileUpload instanceof MemoryFileUpload) {
|
||||||
|
if (fileUpload.length() + buffer.readableBytes() > limitSize) {
|
||||||
|
DiskFileUpload diskFileUpload = new DiskFileUpload(fileUpload
|
||||||
|
.getName(), fileUpload.getFilename(), fileUpload
|
||||||
|
.getContentType(), fileUpload
|
||||||
|
.getContentTransferEncoding(), fileUpload.getCharset(),
|
||||||
|
definedSize);
|
||||||
|
if (((MemoryFileUpload) fileUpload).getByteBuf() != null) {
|
||||||
|
diskFileUpload.addContent(((MemoryFileUpload) fileUpload)
|
||||||
|
.getByteBuf(), false);
|
||||||
|
}
|
||||||
|
fileUpload = diskFileUpload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileUpload.addContent(buffer, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
fileUpload.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] get() throws IOException {
|
||||||
|
return fileUpload.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getByteBuf() throws IOException {
|
||||||
|
return fileUpload.getByteBuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Charset getCharset() {
|
||||||
|
return fileUpload.getCharset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return fileUpload.getContentType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentTransferEncoding() {
|
||||||
|
return fileUpload.getContentTransferEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return fileUpload.getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() throws IOException {
|
||||||
|
return fileUpload.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(Charset encoding) throws IOException {
|
||||||
|
return fileUpload.getString(encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return fileUpload.isCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInMemory() {
|
||||||
|
return fileUpload.isInMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long length() {
|
||||||
|
return fileUpload.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean renameTo(File dest) throws IOException {
|
||||||
|
return fileUpload.renameTo(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharset(Charset charset) {
|
||||||
|
fileUpload.setCharset(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(ByteBuf buffer) throws IOException {
|
||||||
|
if (buffer.readableBytes() > limitSize) {
|
||||||
|
if (fileUpload instanceof MemoryFileUpload) {
|
||||||
|
// change to Disk
|
||||||
|
fileUpload = new DiskFileUpload(fileUpload
|
||||||
|
.getName(), fileUpload.getFilename(), fileUpload
|
||||||
|
.getContentType(), fileUpload
|
||||||
|
.getContentTransferEncoding(), fileUpload.getCharset(),
|
||||||
|
definedSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileUpload.setContent(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(File file) throws IOException {
|
||||||
|
if (file.length() > limitSize) {
|
||||||
|
if (fileUpload instanceof MemoryFileUpload) {
|
||||||
|
// change to Disk
|
||||||
|
fileUpload = new DiskFileUpload(fileUpload
|
||||||
|
.getName(), fileUpload.getFilename(), fileUpload
|
||||||
|
.getContentType(), fileUpload
|
||||||
|
.getContentTransferEncoding(), fileUpload.getCharset(),
|
||||||
|
definedSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileUpload.setContent(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(InputStream inputStream) throws IOException {
|
||||||
|
if (fileUpload instanceof MemoryFileUpload) {
|
||||||
|
// change to Disk
|
||||||
|
fileUpload = new DiskFileUpload(fileUpload
|
||||||
|
.getName(), fileUpload.getFilename(), fileUpload
|
||||||
|
.getContentType(), fileUpload
|
||||||
|
.getContentTransferEncoding(), fileUpload.getCharset(),
|
||||||
|
definedSize);
|
||||||
|
}
|
||||||
|
fileUpload.setContent(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
fileUpload.setContentType(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentTransferEncoding(String contentTransferEncoding) {
|
||||||
|
fileUpload.setContentTransferEncoding(contentTransferEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
fileUpload.setFilename(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpDataType getHttpDataType() {
|
||||||
|
return fileUpload.getHttpDataType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return fileUpload.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(InterfaceHttpData o) {
|
||||||
|
return fileUpload.compareTo(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Mixed: " + fileUpload.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getChunk(int length) throws IOException {
|
||||||
|
return fileUpload.getChunk(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() throws IOException {
|
||||||
|
return fileUpload.getFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP multipart support.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.codec.http.multipart;
|
@ -0,0 +1,974 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.http.upload;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.ClientCookieEncoder;
|
||||||
|
import io.netty.handler.codec.http.DefaultCookie;
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.codec.http.QueryStringEncoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskAttribute;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskFileUpload;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.ErrorDataEncoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||||
|
import io.netty.logging.InternalLogger;
|
||||||
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is meant to be run against {@link HttpUploadServer}.
|
||||||
|
*/
|
||||||
|
public class HttpUploadClient {
|
||||||
|
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadClient.class);
|
||||||
|
|
||||||
|
private final String baseUri;
|
||||||
|
private final String filePath;
|
||||||
|
|
||||||
|
public HttpUploadClient(String baseUri, String filePath) {
|
||||||
|
this.baseUri = baseUri;
|
||||||
|
this.filePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws Exception {
|
||||||
|
String postSimple, postFile, get;
|
||||||
|
if (baseUri.endsWith("/")) {
|
||||||
|
postSimple = baseUri + "formpost";
|
||||||
|
postFile = baseUri + "formpostmultipart";
|
||||||
|
get = baseUri + "formget";
|
||||||
|
} else {
|
||||||
|
postSimple = baseUri + "/formpost";
|
||||||
|
postFile = baseUri + "/formpostmultipart";
|
||||||
|
get = baseUri + "/formget";
|
||||||
|
}
|
||||||
|
URI uriSimple;
|
||||||
|
try {
|
||||||
|
uriSimple = new URI(postSimple);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
logger.error("Invalid URI syntax" + e.getCause());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String scheme = uriSimple.getScheme() == null ? "http" : uriSimple.getScheme();
|
||||||
|
String host = uriSimple.getHost() == null ? "localhost" : uriSimple.getHost();
|
||||||
|
int port = uriSimple.getPort();
|
||||||
|
if (port == -1) {
|
||||||
|
if (scheme.equalsIgnoreCase("http")) {
|
||||||
|
port = 80;
|
||||||
|
} else if (scheme.equalsIgnoreCase("https")) {
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https")) {
|
||||||
|
logger.error("Only HTTP(S) is supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean ssl = scheme.equalsIgnoreCase("https");
|
||||||
|
|
||||||
|
URI uriFile;
|
||||||
|
try {
|
||||||
|
uriFile = new URI(postFile);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
logger.error("Error: " + e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File file = new File(filePath);
|
||||||
|
if (!file.canRead()) {
|
||||||
|
logger.error("A correct path is needed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the client.
|
||||||
|
Bootstrap b = new Bootstrap();
|
||||||
|
b.group(new NioEventLoopGroup()).channel(NioSocketChannel.class).handler(new HttpUploadClientIntializer(ssl));
|
||||||
|
|
||||||
|
// setup the factory: here using a mixed memory/disk based on size threshold
|
||||||
|
HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if MINSIZE exceed
|
||||||
|
|
||||||
|
DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
|
||||||
|
DiskFileUpload.baseDirectory = null; // system temp directory
|
||||||
|
DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit)
|
||||||
|
DiskAttribute.baseDirectory = null; // system temp directory
|
||||||
|
|
||||||
|
// Simple Get form: no factory used (not usable)
|
||||||
|
List<Entry<String, String>> headers = formGet(b, host, port, get, uriSimple);
|
||||||
|
if (headers == null) {
|
||||||
|
factory.cleanAllHttpDatas();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple Post form: factory used for big attributes
|
||||||
|
List<InterfaceHttpData> bodylist = formPost(b, host, port, uriSimple, file, factory, headers);
|
||||||
|
if (bodylist == null) {
|
||||||
|
factory.cleanAllHttpDatas();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multipart Post form: factory used
|
||||||
|
formPostMultipart(b, host, port, uriFile, factory, headers, bodylist);
|
||||||
|
|
||||||
|
// Shut down executor threads to exit.
|
||||||
|
b.shutdown();
|
||||||
|
|
||||||
|
// Really clean all temporary files if they still exist
|
||||||
|
factory.cleanAllHttpDatas();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard usage of HTTP API in Netty without file Upload (get is not able to achieve File upload due to limitation
|
||||||
|
* on request size).
|
||||||
|
*
|
||||||
|
* @return the list of headers that will be used in every example after
|
||||||
|
**/
|
||||||
|
private static List<Entry<String, String>> formGet(Bootstrap bootstrap, String host, int port, String get,
|
||||||
|
URI uriSimple) throws Exception {
|
||||||
|
// Start the connection attempt.
|
||||||
|
// No use of HttpPostRequestEncoder since not a POST
|
||||||
|
bootstrap.remoteAddress(new InetSocketAddress(host, port));
|
||||||
|
Channel channel = bootstrap.connect().sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
QueryStringEncoder encoder = new QueryStringEncoder(get);
|
||||||
|
// add Form attribute
|
||||||
|
encoder.addParam("getform", "GET");
|
||||||
|
encoder.addParam("info", "first value");
|
||||||
|
encoder.addParam("secondinfo", "secondvalue <20><><EFBFBD>&");
|
||||||
|
// not the big one since it is not compatible with GET size
|
||||||
|
// encoder.addParam("thirdinfo", textArea);
|
||||||
|
encoder.addParam("thirdinfo", "third value\r\ntest second line\r\n\r\nnew line\r\n");
|
||||||
|
encoder.addParam("Send", "Send");
|
||||||
|
|
||||||
|
URI uriGet;
|
||||||
|
try {
|
||||||
|
uriGet = new URI(encoder.toString());
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
logger.error("Error: " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
|
||||||
|
request.setHeader(HttpHeaders.Names.HOST, host);
|
||||||
|
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
|
||||||
|
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ","
|
||||||
|
+ HttpHeaders.Values.DEFLATE);
|
||||||
|
|
||||||
|
request.setHeader(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
|
||||||
|
request.setHeader(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");
|
||||||
|
request.setHeader(HttpHeaders.Names.REFERER, uriSimple.toString());
|
||||||
|
request.setHeader(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side");
|
||||||
|
request.setHeader(HttpHeaders.Names.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||||
|
|
||||||
|
// connection will not close but needed
|
||||||
|
// request.setHeader("Connection","keep-alive");
|
||||||
|
// request.setHeader("Keep-Alive","300");
|
||||||
|
|
||||||
|
request.setHeader(HttpHeaders.Names.COOKIE, ClientCookieEncoder.encode(new DefaultCookie("my-cookie", "foo"),
|
||||||
|
new DefaultCookie("another-cookie", "bar")));
|
||||||
|
|
||||||
|
// send request
|
||||||
|
List<Entry<String, String>> headers = request.getHeaders();
|
||||||
|
channel.write(request);
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
channel.closeFuture().sync();
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard post without multipart but already support on Factory (memory management)
|
||||||
|
*
|
||||||
|
* @return the list of HttpData object (attribute and file) to be reused on next post
|
||||||
|
*/
|
||||||
|
private static List<InterfaceHttpData> formPost(Bootstrap bootstrap, String host, int port, URI uriSimple,
|
||||||
|
File file, HttpDataFactory factory, List<Entry<String, String>> headers) throws Exception {
|
||||||
|
|
||||||
|
// Start the connection attempt
|
||||||
|
bootstrap.remoteAddress(new InetSocketAddress(host, port));
|
||||||
|
Channel channel = bootstrap.connect().sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());
|
||||||
|
|
||||||
|
// Use the PostBody encoder
|
||||||
|
HttpPostRequestEncoder bodyRequestEncoder = null;
|
||||||
|
try {
|
||||||
|
bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false); // false not multipart
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// should not be since args are not null
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ErrorDataEncoderException e) {
|
||||||
|
// test if method is a POST method
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is legal to add directly header or cookie into the request until finalize
|
||||||
|
for (Entry<String, String> entry : headers) {
|
||||||
|
request.setHeader(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add Form attribute
|
||||||
|
try {
|
||||||
|
bodyRequestEncoder.addBodyAttribute("getform", "POST");
|
||||||
|
bodyRequestEncoder.addBodyAttribute("info", "first value");
|
||||||
|
bodyRequestEncoder.addBodyAttribute("secondinfo", "secondvalue <20><><EFBFBD>&");
|
||||||
|
bodyRequestEncoder.addBodyAttribute("thirdinfo", textArea);
|
||||||
|
bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false);
|
||||||
|
bodyRequestEncoder.addBodyAttribute("Send", "Send");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// should not be since not null args
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ErrorDataEncoderException e) {
|
||||||
|
// if an encoding error occurs
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize request
|
||||||
|
try {
|
||||||
|
request = bodyRequestEncoder.finalizeRequest();
|
||||||
|
} catch (ErrorDataEncoderException e) {
|
||||||
|
// if an encoding error occurs
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the bodylist to be reused on the last version with Multipart support
|
||||||
|
List<InterfaceHttpData> bodylist = bodyRequestEncoder.getBodyListAttributes();
|
||||||
|
|
||||||
|
// send request
|
||||||
|
channel.write(request);
|
||||||
|
|
||||||
|
// test if request was chunked and if so, finish the write
|
||||||
|
if (bodyRequestEncoder.isChunked()) {
|
||||||
|
// could do either request.isChunked()
|
||||||
|
// either do it through ChunkedWriteHandler
|
||||||
|
channel.write(bodyRequestEncoder).awaitUninterruptibly();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not clear here since we will reuse the InterfaceHttpData on the
|
||||||
|
// next request
|
||||||
|
// for the example (limit action on client side). Take this as a
|
||||||
|
// broadcast of the same
|
||||||
|
// request on both Post actions.
|
||||||
|
//
|
||||||
|
// On standard program, it is clearly recommended to clean all files
|
||||||
|
// after each request
|
||||||
|
// bodyRequestEncoder.cleanFiles();
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
channel.closeFuture().sync();
|
||||||
|
|
||||||
|
return bodylist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multipart example
|
||||||
|
*/
|
||||||
|
private static void formPostMultipart(Bootstrap bootstrap, String host, int port, URI uriFile,
|
||||||
|
HttpDataFactory factory, List<Entry<String, String>> headers, List<InterfaceHttpData> bodylist)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
// Start the connection attempt
|
||||||
|
bootstrap.remoteAddress(new InetSocketAddress(host, port));
|
||||||
|
Channel channel = bootstrap.connect().sync().channel();
|
||||||
|
|
||||||
|
// Prepare the HTTP request.
|
||||||
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString());
|
||||||
|
|
||||||
|
// Use the PostBody encoder
|
||||||
|
HttpPostRequestEncoder bodyRequestEncoder = null;
|
||||||
|
try {
|
||||||
|
bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, true); // true => multipart
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// should not be since no null args
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ErrorDataEncoderException e) {
|
||||||
|
// test if method is a POST method
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is legal to add directly header or cookie into the request until finalize
|
||||||
|
for (Entry<String, String> entry : headers) {
|
||||||
|
request.setHeader(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add Form attribute from previous request in formpost()
|
||||||
|
try {
|
||||||
|
bodyRequestEncoder.setBodyHttpDatas(bodylist);
|
||||||
|
} catch (NullPointerException e1) {
|
||||||
|
// should not be since previously created
|
||||||
|
e1.printStackTrace();
|
||||||
|
} catch (ErrorDataEncoderException e1) {
|
||||||
|
// again should not be since previously encoded (except if an error
|
||||||
|
// occurs previously)
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize request
|
||||||
|
try {
|
||||||
|
bodyRequestEncoder.finalizeRequest();
|
||||||
|
} catch (ErrorDataEncoderException e) {
|
||||||
|
// if an encoding error occurs
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// send request
|
||||||
|
channel.write(request);
|
||||||
|
|
||||||
|
// test if request was chunked and if so, finish the write
|
||||||
|
if (bodyRequestEncoder.isChunked()) {
|
||||||
|
channel.write(bodyRequestEncoder).awaitUninterruptibly();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now no more use of file representation (and list of HttpData)
|
||||||
|
bodyRequestEncoder.cleanFiles();
|
||||||
|
|
||||||
|
// Wait for the server to close the connection.
|
||||||
|
channel.closeFuture().sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String baseUri;
|
||||||
|
String filePath;
|
||||||
|
if (args.length == 2) {
|
||||||
|
baseUri = args[0];
|
||||||
|
filePath = args[1];
|
||||||
|
} else {
|
||||||
|
baseUri = "http://localhost:8080";
|
||||||
|
|
||||||
|
File f = File.createTempFile("upload", ".txt");
|
||||||
|
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
|
||||||
|
bw.write("Some text data in a file to be posted");
|
||||||
|
bw.close();
|
||||||
|
filePath = f.getPath();
|
||||||
|
f.deleteOnExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Posting to " + baseUri + ". Using file " + filePath);
|
||||||
|
new HttpUploadClient(baseUri, filePath).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// use to simulate a small TEXTAREA field in a form
|
||||||
|
private static final String textArea = "short text";
|
||||||
|
// use to simulate a big TEXTAREA field in a form
|
||||||
|
/*
|
||||||
|
private static final String textAreaLong =
|
||||||
|
"lkjlkjlKJLKJLKJLKJLJlkj lklkj\r\n\r\nLKJJJJJJJJKKKKKKKKKKKKKKK <20><><EFBFBD><EFBFBD>&\r\n\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
|
||||||
|
+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n";
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.http.upload;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||||
|
import io.netty.handler.codec.http.HttpChunk;
|
||||||
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
|
import io.netty.logging.InternalLogger;
|
||||||
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler that just dumps the contents of the response from the server
|
||||||
|
*/
|
||||||
|
public class HttpUploadClientHandler extends ChannelInboundMessageHandlerAdapter<Object> {
|
||||||
|
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadClientHandler.class);
|
||||||
|
|
||||||
|
private boolean readingChunks;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
if (!readingChunks) {
|
||||||
|
HttpResponse response = (HttpResponse) msg;
|
||||||
|
|
||||||
|
logger.info("STATUS: " + response.getStatus());
|
||||||
|
logger.info("VERSION: " + response.getProtocolVersion());
|
||||||
|
|
||||||
|
if (!response.getHeaderNames().isEmpty()) {
|
||||||
|
for (String name : response.getHeaderNames()) {
|
||||||
|
for (String value : response.getHeaders(name)) {
|
||||||
|
logger.info("HEADER: " + name + " = " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.getStatus().getCode() == 200 && response.getTransferEncoding().isMultiple()) {
|
||||||
|
readingChunks = true;
|
||||||
|
logger.info("CHUNKED CONTENT {");
|
||||||
|
} else {
|
||||||
|
ByteBuf content = response.getContent();
|
||||||
|
if (content.readable()) {
|
||||||
|
logger.info("CONTENT {");
|
||||||
|
logger.info(content.toString(CharsetUtil.UTF_8));
|
||||||
|
logger.info("} END OF CONTENT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HttpChunk chunk = (HttpChunk) msg;
|
||||||
|
if (chunk.isLast()) {
|
||||||
|
readingChunks = false;
|
||||||
|
logger.info("} END OF CHUNKED CONTENT");
|
||||||
|
} else {
|
||||||
|
logger.info(chunk.getContent().toString(CharsetUtil.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.channel().close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.http.upload;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.example.securechat.SecureChatSslContextFactory;
|
||||||
|
import io.netty.handler.codec.http.HttpClientCodec;
|
||||||
|
import io.netty.handler.codec.http.HttpContentDecompressor;
|
||||||
|
import io.netty.handler.ssl.SslHandler;
|
||||||
|
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
|
||||||
|
public class HttpUploadClientIntializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
private final boolean ssl;
|
||||||
|
|
||||||
|
public HttpUploadClientIntializer(boolean ssl) {
|
||||||
|
this.ssl = ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
// Create a default pipeline implementation.
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
|
||||||
|
if (ssl) {
|
||||||
|
SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine();
|
||||||
|
engine.setUseClientMode(true);
|
||||||
|
pipeline.addLast("ssl", new SslHandler(engine));
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline.addLast("codec", new HttpClientCodec());
|
||||||
|
|
||||||
|
// Remove the following line if you don't want automatic content decompression.
|
||||||
|
pipeline.addLast("inflater", new HttpContentDecompressor());
|
||||||
|
|
||||||
|
// to be used since huge file transfer
|
||||||
|
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
|
||||||
|
|
||||||
|
pipeline.addLast("handler", new HttpUploadClientHandler());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.http.upload;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A HTTP server showing how to use the HTTP multipart package for file uploads and decoding post data.
|
||||||
|
*/
|
||||||
|
public class HttpUploadServer {
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
public static boolean isSSL;
|
||||||
|
|
||||||
|
public HttpUploadServer(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws Exception {
|
||||||
|
ServerBootstrap b = new ServerBootstrap();
|
||||||
|
try {
|
||||||
|
b.group(new NioEventLoopGroup(), new NioEventLoopGroup()).channel(NioServerSocketChannel.class)
|
||||||
|
.localAddress(port).childHandler(new HttpUploadServerInitializer());
|
||||||
|
|
||||||
|
Channel ch = b.bind().sync().channel();
|
||||||
|
System.out.println("HTTP Upload Server at port " + port + '.');
|
||||||
|
System.out.println("Open your browser and navigate to http://localhost:" + port + '/');
|
||||||
|
|
||||||
|
ch.closeFuture().sync();
|
||||||
|
} finally {
|
||||||
|
b.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
int port;
|
||||||
|
if (args.length > 0) {
|
||||||
|
port = Integer.parseInt(args[0]);
|
||||||
|
} else {
|
||||||
|
port = 8080;
|
||||||
|
}
|
||||||
|
if (args.length > 1) {
|
||||||
|
isSSL = true;
|
||||||
|
}
|
||||||
|
new HttpUploadServer(port).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,427 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.http.upload;
|
||||||
|
|
||||||
|
import static io.netty.buffer.Unpooled.copiedBuffer;
|
||||||
|
import static io.netty.handler.codec.http.HttpHeaders.Names.SET_COOKIE;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||||
|
import io.netty.handler.codec.http.Cookie;
|
||||||
|
import io.netty.handler.codec.http.CookieDecoder;
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpChunk;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||||
|
import io.netty.handler.codec.http.ServerCookieEncoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.Attribute;
|
||||||
|
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskAttribute;
|
||||||
|
import io.netty.handler.codec.http.multipart.DiskFileUpload;
|
||||||
|
import io.netty.handler.codec.http.multipart.FileUpload;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpDataFactory;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.IncompatibleDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
|
||||||
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||||
|
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
|
||||||
|
import io.netty.logging.InternalLogger;
|
||||||
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter<Object> {
|
||||||
|
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadServerHandler.class);
|
||||||
|
|
||||||
|
private HttpRequest request;
|
||||||
|
|
||||||
|
private boolean readingChunks;
|
||||||
|
|
||||||
|
private final StringBuilder responseContent = new StringBuilder();
|
||||||
|
|
||||||
|
private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk
|
||||||
|
// if
|
||||||
|
// size
|
||||||
|
// exceed
|
||||||
|
|
||||||
|
private HttpPostRequestDecoder decoder;
|
||||||
|
static {
|
||||||
|
DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file
|
||||||
|
// on exit (in normal
|
||||||
|
// exit)
|
||||||
|
DiskFileUpload.baseDirectory = null; // system temp directory
|
||||||
|
DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on
|
||||||
|
// exit (in normal exit)
|
||||||
|
DiskAttribute.baseDirectory = null; // system temp directory
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
if (decoder != null) {
|
||||||
|
decoder.cleanFiles();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
if (!readingChunks) {
|
||||||
|
// clean previous FileUpload if Any
|
||||||
|
if (decoder != null) {
|
||||||
|
decoder.cleanFiles();
|
||||||
|
decoder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest request = this.request = (HttpRequest) msg;
|
||||||
|
URI uri = new URI(request.getUri());
|
||||||
|
if (!uri.getPath().startsWith("/form")) {
|
||||||
|
// Write Menu
|
||||||
|
writeMenu(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
responseContent.setLength(0);
|
||||||
|
responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
|
||||||
|
responseContent.append("===================================\r\n");
|
||||||
|
|
||||||
|
responseContent.append("VERSION: " + request.getProtocolVersion().getText() + "\r\n");
|
||||||
|
|
||||||
|
responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n");
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
// new method
|
||||||
|
List<Entry<String, String>> headers = request.getHeaders();
|
||||||
|
for (Entry<String, String> entry : headers) {
|
||||||
|
responseContent.append("HEADER: " + entry.getKey() + "=" + entry.getValue() + "\r\n");
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
// new method
|
||||||
|
Set<Cookie> cookies;
|
||||||
|
String value = request.getHeader(HttpHeaders.Names.COOKIE);
|
||||||
|
if (value == null) {
|
||||||
|
cookies = Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
cookies = CookieDecoder.decode(value);
|
||||||
|
}
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
responseContent.append("COOKIE: " + cookie.toString() + "\r\n");
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri());
|
||||||
|
Map<String, List<String>> uriAttributes = decoderQuery.getParameters();
|
||||||
|
for (String key : uriAttributes.keySet()) {
|
||||||
|
for (String valuen : uriAttributes.get(key)) {
|
||||||
|
responseContent.append("URI: " + key + "=" + valuen + "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\n");
|
||||||
|
|
||||||
|
// if GET Method: should not try to create a HttpPostRequestDecoder
|
||||||
|
try {
|
||||||
|
decoder = new HttpPostRequestDecoder(factory, request);
|
||||||
|
} catch (ErrorDataDecoderException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
responseContent.append(e1.getMessage());
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
ctx.channel().close();
|
||||||
|
return;
|
||||||
|
} catch (IncompatibleDataDecoderException e1) {
|
||||||
|
// GET Method: should not try to create a HttpPostRequestDecoder
|
||||||
|
// So OK but stop here
|
||||||
|
responseContent.append(e1.getMessage());
|
||||||
|
responseContent.append("\r\n\r\nEND OF GET CONTENT\r\n");
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
responseContent.append("Is Chunked: " + request.getTransferEncoding().isMultiple() + "\r\n");
|
||||||
|
responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n");
|
||||||
|
if (request.getTransferEncoding().isMultiple()) {
|
||||||
|
// Chunk version
|
||||||
|
responseContent.append("Chunks: ");
|
||||||
|
readingChunks = true;
|
||||||
|
} else {
|
||||||
|
// Not chunk version
|
||||||
|
readHttpDataAllReceive(ctx.channel());
|
||||||
|
responseContent.append("\r\n\r\nEND OF NOT CHUNKED CONTENT\r\n");
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// New chunk is received
|
||||||
|
HttpChunk chunk = (HttpChunk) msg;
|
||||||
|
try {
|
||||||
|
decoder.offer(chunk);
|
||||||
|
} catch (ErrorDataDecoderException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
responseContent.append(e1.getMessage());
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
ctx.channel().close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
responseContent.append("o");
|
||||||
|
// example of reading chunk by chunk (minimize memory usage due to
|
||||||
|
// Factory)
|
||||||
|
readHttpDataChunkByChunk(ctx.channel());
|
||||||
|
// example of reading only if at the end
|
||||||
|
if (chunk.isLast()) {
|
||||||
|
readHttpDataAllReceive(ctx.channel());
|
||||||
|
writeResponse(ctx.channel());
|
||||||
|
readingChunks = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of reading all InterfaceHttpData from finished transfer
|
||||||
|
*
|
||||||
|
* @param channel
|
||||||
|
*/
|
||||||
|
private void readHttpDataAllReceive(Channel channel) {
|
||||||
|
List<InterfaceHttpData> datas = null;
|
||||||
|
try {
|
||||||
|
datas = decoder.getBodyHttpDatas();
|
||||||
|
} catch (NotEnoughDataDecoderException e1) {
|
||||||
|
// Should not be!
|
||||||
|
e1.printStackTrace();
|
||||||
|
responseContent.append(e1.getMessage());
|
||||||
|
writeResponse(channel);
|
||||||
|
channel.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (InterfaceHttpData data : datas) {
|
||||||
|
writeHttpData(data);
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n\r\nEND OF CONTENT AT FINAL END\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example of reading request by chunk and getting values from chunk to chunk
|
||||||
|
*
|
||||||
|
* @param channel
|
||||||
|
*/
|
||||||
|
private void readHttpDataChunkByChunk(Channel channel) {
|
||||||
|
try {
|
||||||
|
while (decoder.hasNext()) {
|
||||||
|
InterfaceHttpData data = decoder.next();
|
||||||
|
if (data != null) {
|
||||||
|
// new value
|
||||||
|
writeHttpData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (EndOfDataDecoderException e1) {
|
||||||
|
// end
|
||||||
|
responseContent.append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeHttpData(InterfaceHttpData data) {
|
||||||
|
if (data.getHttpDataType() == HttpDataType.Attribute) {
|
||||||
|
Attribute attribute = (Attribute) data;
|
||||||
|
String value;
|
||||||
|
try {
|
||||||
|
value = attribute.getValue();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
// Error while reading data from File, only print name and error
|
||||||
|
e1.printStackTrace();
|
||||||
|
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
|
||||||
|
+ attribute.getName() + " Error while reading value: " + e1.getMessage() + "\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.length() > 100) {
|
||||||
|
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
|
||||||
|
+ attribute.getName() + " data too long\r\n");
|
||||||
|
} else {
|
||||||
|
responseContent.append("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": "
|
||||||
|
+ attribute.toString() + "\r\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
responseContent.append("\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data.toString()
|
||||||
|
+ "\r\n");
|
||||||
|
if (data.getHttpDataType() == HttpDataType.FileUpload) {
|
||||||
|
FileUpload fileUpload = (FileUpload) data;
|
||||||
|
if (fileUpload.isCompleted()) {
|
||||||
|
if (fileUpload.length() < 10000) {
|
||||||
|
responseContent.append("\tContent of file\r\n");
|
||||||
|
try {
|
||||||
|
responseContent.append(((FileUpload) data).getString(((FileUpload) data).getCharset()));
|
||||||
|
} catch (IOException e1) {
|
||||||
|
// do nothing for the example
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
responseContent.append("\r\n");
|
||||||
|
} else {
|
||||||
|
responseContent.append("\tFile too long to be printed out:" + fileUpload.length() + "\r\n");
|
||||||
|
}
|
||||||
|
// fileUpload.isInMemory();// tells if the file is in Memory
|
||||||
|
// or on File
|
||||||
|
// fileUpload.renameTo(dest); // enable to move into another
|
||||||
|
// File dest
|
||||||
|
// decoder.removeFileUploadFromClean(fileUpload); //remove
|
||||||
|
// the File of to delete file
|
||||||
|
} else {
|
||||||
|
responseContent.append("\tFile to be continued but should not!\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeResponse(Channel channel) {
|
||||||
|
// Convert the response content to a ChannelBuffer.
|
||||||
|
ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
|
||||||
|
responseContent.setLength(0);
|
||||||
|
|
||||||
|
// Decide whether to close the connection or not.
|
||||||
|
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.getHeader(HttpHeaders.Names.CONNECTION))
|
||||||
|
|| request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)
|
||||||
|
&& !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.getHeader(HttpHeaders.Names.CONNECTION));
|
||||||
|
|
||||||
|
// Build the response object.
|
||||||
|
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||||
|
response.setContent(buf);
|
||||||
|
response.setHeader(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||||
|
|
||||||
|
if (!close) {
|
||||||
|
// There's no need to add 'Content-Length' header
|
||||||
|
// if this is the last response.
|
||||||
|
response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Cookie> cookies;
|
||||||
|
String value = request.getHeader(HttpHeaders.Names.COOKIE);
|
||||||
|
if (value == null) {
|
||||||
|
cookies = Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
cookies = CookieDecoder.decode(value);
|
||||||
|
}
|
||||||
|
if (!cookies.isEmpty()) {
|
||||||
|
// Reset the cookies if necessary.
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
response.addHeader(SET_COOKIE, ServerCookieEncoder.encode(cookie));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write the response.
|
||||||
|
ChannelFuture future = channel.write(response);
|
||||||
|
// Close the connection after the write operation is done if necessary.
|
||||||
|
if (close) {
|
||||||
|
future.addListener(ChannelFutureListener.CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeMenu(ChannelHandlerContext ctx) {
|
||||||
|
// print several HTML forms
|
||||||
|
// Convert the response content to a ChannelBuffer.
|
||||||
|
responseContent.setLength(0);
|
||||||
|
|
||||||
|
// create Pseudo Menu
|
||||||
|
responseContent.append("<html>");
|
||||||
|
responseContent.append("<head>");
|
||||||
|
responseContent.append("<title>Netty Test Form</title>\r\n");
|
||||||
|
responseContent.append("</head>\r\n");
|
||||||
|
responseContent.append("<body bgcolor=white><style>td{font-size: 12pt;}</style>");
|
||||||
|
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr>");
|
||||||
|
responseContent.append("<td>");
|
||||||
|
responseContent.append("<h1>Netty Test Form</h1>");
|
||||||
|
responseContent.append("Choose one FORM");
|
||||||
|
responseContent.append("</td>");
|
||||||
|
responseContent.append("</tr>");
|
||||||
|
responseContent.append("</table>\r\n");
|
||||||
|
|
||||||
|
// GET
|
||||||
|
responseContent.append("<CENTER>GET FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
responseContent.append("<FORM ACTION=\"/formget\" METHOD=\"GET\">");
|
||||||
|
responseContent.append("<input type=hidden name=getform value=\"GET\">");
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
|
||||||
|
responseContent
|
||||||
|
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
|
||||||
|
responseContent.append("</td></tr>");
|
||||||
|
responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
|
||||||
|
responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
|
||||||
|
responseContent.append("</table></FORM>\r\n");
|
||||||
|
responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
|
||||||
|
// POST
|
||||||
|
responseContent.append("<CENTER>POST FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
responseContent.append("<FORM ACTION=\"/formpost\" METHOD=\"POST\">");
|
||||||
|
responseContent.append("<input type=hidden name=getform value=\"POST\">");
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
|
||||||
|
responseContent
|
||||||
|
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
|
||||||
|
responseContent.append("<tr><td>Fill with file (only file name will be transmitted): <br> "
|
||||||
|
+ "<input type=file name=\"myfile\">");
|
||||||
|
responseContent.append("</td></tr>");
|
||||||
|
responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
|
||||||
|
responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
|
||||||
|
responseContent.append("</table></FORM>\r\n");
|
||||||
|
responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
|
||||||
|
// POST with enctype="multipart/form-data"
|
||||||
|
responseContent.append("<CENTER>POST MULTIPART FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
responseContent.append("<FORM ACTION=\"/formpostmultipart\" ENCTYPE=\"multipart/form-data\" METHOD=\"POST\">");
|
||||||
|
responseContent.append("<input type=hidden name=getform value=\"POST\">");
|
||||||
|
responseContent.append("<table border=\"0\">");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"info\" size=10></td></tr>");
|
||||||
|
responseContent.append("<tr><td>Fill with value: <br> <input type=text name=\"secondinfo\" size=20>");
|
||||||
|
responseContent
|
||||||
|
.append("<tr><td>Fill with value: <br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
|
||||||
|
responseContent.append("<tr><td>Fill with file: <br> <input type=file name=\"myfile\">");
|
||||||
|
responseContent.append("</td></tr>");
|
||||||
|
responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
|
||||||
|
responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
|
||||||
|
responseContent.append("</table></FORM>\r\n");
|
||||||
|
responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
|
||||||
|
|
||||||
|
responseContent.append("</body>");
|
||||||
|
responseContent.append("</html>");
|
||||||
|
|
||||||
|
ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
|
||||||
|
// Build the response object.
|
||||||
|
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||||
|
response.setContent(buf);
|
||||||
|
response.setHeader(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||||
|
response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
|
||||||
|
// Write the response.
|
||||||
|
ctx.channel().write(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
logger.error(responseContent.toString(), cause);
|
||||||
|
ctx.channel().close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.http.upload;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.example.securechat.SecureChatSslContextFactory;
|
||||||
|
import io.netty.handler.codec.http.HttpContentCompressor;
|
||||||
|
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
|
import io.netty.handler.ssl.SslHandler;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
|
||||||
|
public class HttpUploadServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
@Override
|
||||||
|
public void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
// Create a default pipeline implementation.
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
|
||||||
|
if (HttpUploadServer.isSSL) {
|
||||||
|
SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
|
||||||
|
engine.setUseClientMode(false);
|
||||||
|
pipeline.addLast("ssl", new SslHandler(engine));
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline.addLast("decoder", new HttpRequestDecoder());
|
||||||
|
pipeline.addLast("encoder", new HttpResponseEncoder());
|
||||||
|
|
||||||
|
// Remove the following line if you don't want automatic content
|
||||||
|
// compression.
|
||||||
|
pipeline.addLast("deflater", new HttpContentCompressor());
|
||||||
|
|
||||||
|
pipeline.addLast("handler", new HttpUploadServerHandler());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user