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) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (b.readable()) {
|
||||
addComponent(cIndex ++, b);
|
||||
int size = components.size();
|
||||
if (cIndex > size) {
|
||||
// was consolidated, so adjust index. #707
|
||||
cIndex = size;
|
||||
}
|
||||
// Always add b to the end of the component list because we are appending buffers
|
||||
addComponent(components.size(), b);
|
||||
}
|
||||
}
|
||||
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