I need assistance in configuring HTTP-Appender in log4j2.xml. I have made multiple attempt to configure it using both JSONLayout and PatternLayout, neither worked. Here is my code snippet.
<Http name="HTTP_APPENDER" url="http://localhost:8080/test/logRest" method="POST">
<Property name="x-java-runtime" value="$${java:runtime}" />
<PatternLayout pattern="%-5p | %d{yyyy-MM-dd HH:mm:ss} | [%t] %C{2} (%F:%L) - %m%n"/>
</Http>
=====================================================================
#RequestMapping(value = "/logRest", method = RequestMethod.POST)
public void logRest(HttpServletRequest request,HttpServletResponse response, Model model){
Enumeration<String> y = request.getHeaderNames();
while (y.hasMoreElements()) {
String param = y.nextElement();
String value = request.getHeader(param);
System.out.println(param + "=" + value);
}
System.out.println("====================================");
Enumeration<String> x = request.getParameterNames();
while (x.hasMoreElements()) {
String param = x.nextElement();
String value = request.getParameter(param);
System.out.println(param + "=" + value);
}
}
==================================================================
I need to get the logged data, but it's not showing in the header,parameter or even the request attributes. I will appreciate any form of assistance to get the logged data sent to the URL endpoint.
Cheers.
See the solution below
/**
* Reads the request body from the request and returns it as a String.
*
* #param request HttpServletRequest that contains the request body
* #return request body as a String or null
*/
private String readRequestBody(HttpServletRequest request) {
try {
// Read from request
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
} catch (Exception e) {
//logger.error("Failed to read the request body from the request.");
}
return null;
}
Related
Folks,
I am trying to move data to s3 from Salesforce using apex class. I have been told by the data manager to send the data in zip/gzip format to the S3 bucket for storage cost savings.
I have simply tried to do a request.setCompressed(true); as I've read it compresses the body before sending it to the endpoint. Code below:
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:'+DATA_NAMED_CRED+'/'+URL+'/'+generateUniqueTimeStampforSuffix());
request.setMethod('PUT');
request.setBody(JSON.serialize(data));
request.setCompressed(true);
request.setHeader('Content-Type','application/json');
But no matter what I always receive this:
<Error><Code>XAmzContentSHA256Mismatch</Code><Message>The provided 'x-amz-content-sha256' header does not match what was computed.</Message><ClientComputedContentSHA256>fd31b2b9115ef77e8076b896cb336d21d8f66947210ffcc9c4d1971b2be3bbbc</ClientComputedContentSHA256><S3ComputedContentSHA256>1e7f2115e60132afed9e61132aa41c3224c6e305ad9f820e6893364d7257ab8d</S3ComputedContentSHA256>
I have tried multiple headers too, like setting the content type to gzip/zip, etc.
Any pointers in the right direction would be appreciated.
I had a good amount of headaches attempting to do a similar thing. I feel your pain.
The following code has worked for us using lambda functions; you can try modifying it and see what happens.
public class AwsApiGateway {
// Things we need to know about the service. Set these values in init()
String host, payloadSha256;
String resource;
String service = 'execute-api';
String region;
public Url endpoint;
String accessKey;
String stage;
string secretKey;
HttpMethod method = HttpMethod.XGET;
// Remember to set "payload" here if you need to specify a body
// payload = Blob.valueOf('some-text-i-want-to-send');
// This method helps prevent leaking secret key,
// as it is never serialized
// Url endpoint;
// HttpMethod method;
Blob payload;
// Not used externally, so we hide these values
Blob signingKey;
DateTime requestTime;
Map<String, String> queryParams = new map<string,string>(), headerParams = new map<string,string>();
void init(){
if (payload == null) payload = Blob.valueOf('');
requestTime = DateTime.now();
createSigningKey(secretKey);
}
public AwsApiGateway(String resource){
this.stage = AWS_LAMBDA_STAGE
this.resource = '/' + stage + '/' + resource;
this.region = AWS_REGION;
this.endpoint = new Url(AWS_ENDPOINT);
this.accessKey = AWS_ACCESS_KEY;
this.secretKey = AWS_SECRET_KEY;
}
// Make sure we can't misspell methods
public enum HttpMethod { XGET, XPUT, XHEAD, XOPTIONS, XDELETE, XPOST }
public void setMethod (HttpMethod method){
this.method = method;
}
public void setPayload (string payload){
this.payload = Blob.valueOf(payload);
}
// Add a header
public void setHeader(String key, String value) {
headerParams.put(key.toLowerCase(), value);
}
// Add a query param
public void setQueryParam(String key, String value) {
queryParams.put(key.toLowerCase(), uriEncode(value));
}
// Create a canonical query string (used during signing)
String createCanonicalQueryString() {
String[] results = new String[0], keys = new List<String>(queryParams.keySet());
keys.sort();
for(String key: keys) {
results.add(key+'='+queryParams.get(key));
}
return String.join(results, '&');
}
// Create the canonical headers (used for signing)
String createCanonicalHeaders(String[] keys) {
keys.addAll(headerParams.keySet());
keys.sort();
String[] results = new String[0];
for(String key: keys) {
results.add(key+':'+headerParams.get(key));
}
return String.join(results, '\n')+'\n';
}
// Create the entire canonical request
String createCanonicalRequest(String[] headerKeys) {
return String.join(
new String[] {
method.name().removeStart('X'), // METHOD
new Url(endPoint, resource).getPath(), // RESOURCE
createCanonicalQueryString(), // CANONICAL QUERY STRING
createCanonicalHeaders(headerKeys), // CANONICAL HEADERS
String.join(headerKeys, ';'), // SIGNED HEADERS
payloadSha256 // SHA256 PAYLOAD
},
'\n'
);
}
// We have to replace ~ and " " correctly, or we'll break AWS on those two characters
string uriEncode(String value) {
return value==null? null: EncodingUtil.urlEncode(value, 'utf-8').replaceAll('%7E','~').replaceAll('\\+','%20');
}
// Create the entire string to sign
String createStringToSign(String[] signedHeaders) {
String result = createCanonicalRequest(signedHeaders);
return String.join(
new String[] {
'AWS4-HMAC-SHA256',
headerParams.get('date'),
String.join(new String[] { requestTime.formatGMT('yyyyMMdd'), region, service, 'aws4_request' },'/'),
EncodingUtil.convertToHex(Crypto.generateDigest('sha256', Blob.valueof(result)))
},
'\n'
);
}
// Create our signing key
void createSigningKey(String secretKey) {
signingKey = Crypto.generateMac('hmacSHA256', Blob.valueOf('aws4_request'),
Crypto.generateMac('hmacSHA256', Blob.valueOf(service),
Crypto.generateMac('hmacSHA256', Blob.valueOf(region),
Crypto.generateMac('hmacSHA256', Blob.valueOf(requestTime.formatGMT('yyyyMMdd')), Blob.valueOf('AWS4'+secretKey))
)
)
);
}
// Create all of the bits and pieces using all utility functions above
public HttpRequest createRequest() {
init();
payloadSha256 = EncodingUtil.convertToHex(Crypto.generateDigest('sha-256', payload));
setHeader('date', requestTime.formatGMT('yyyyMMdd\'T\'HHmmss\'Z\''));
if(host == null) {
host = endpoint.getHost();
}
setHeader('host', host);
HttpRequest request = new HttpRequest();
request.setMethod(method.name().removeStart('X'));
if(payload.size() > 0) {
setHeader('Content-Length', String.valueOf(payload.size()));
request.setBodyAsBlob(payload);
}
String finalEndpoint = new Url(endpoint, resource).toExternalForm(),
queryString = createCanonicalQueryString();
if(queryString != '') {
finalEndpoint += '?'+queryString;
}
request.setEndpoint(finalEndpoint);
for(String key: headerParams.keySet()) {
request.setHeader(key, headerParams.get(key));
}
String[] headerKeys = new String[0];
String stringToSign = createStringToSign(headerKeys);
request.setHeader(
'Authorization',
String.format(
'AWS4-HMAC-SHA256 Credential={0}, SignedHeaders={1},Signature={2}',
new String[] {
String.join(new String[] { accessKey, requestTime.formatGMT('yyyyMMdd'), region, service, 'aws4_request' },'/'),
String.join(headerKeys,';'), EncodingUtil.convertToHex(Crypto.generateMac('hmacSHA256', Blob.valueOf(stringToSign), signingKey))}
));
system.debug(json.serializePretty(request.getEndpoint()));
return request;
}
// Actually perform the request, and throw exception if response code is not valid
public HttpResponse sendRequest(Set<Integer> validCodes) {
HttpResponse response = new Http().send(createRequest());
if(!validCodes.contains(response.getStatusCode())) {
system.debug(json.deserializeUntyped(response.getBody()));
}
return response;
}
// Same as above, but assume that only 200 is valid
// This method exists because most of the time, 200 is what we expect
public HttpResponse sendRequest() {
return sendRequest(new Set<Integer> { 200 });
}
// TEST METHODS
public static string getEndpoint(string attribute){
AwsApiGateway api = new AwsApiGateway(attribute);
return api.createRequest().getEndpoint();
}
public static string getEndpoint(string attribute, map<string, string> params){
AwsApiGateway api = new AwsApiGateway(attribute);
for (string key: params.keySet()){
api.setQueryParam(key, params.get(key));
}
return api.createRequest().getEndpoint();
}
public class EndpointConfig {
string resource;
string attribute;
list<object> items;
map<string,string> params;
public EndpointConfig(string resource, string attribute, list<object> items){
this.items = items;
this.resource = resource;
this.attribute = attribute;
}
public EndpointConfig setQueryParams(map<string,string> parameters){
params = parameters;
return this;
}
public string endpoint(){
if (params == null){
return getEndpoint(resource);
} else return getEndpoint(resource + '/' + attribute, params);
}
public SingleRequestMock mockResponse(){
return new SingleRequestMock(200, 'OK', json.serialize(items), null);
}
}
}
I am using CommonsMultipartResolver to upload a word/pdf file into postgres database, while uploading the file I have printed the byte[] array using file.getBytes(), it showing like
bytes==========================[B#6b02547c
the file is being upload but when I download the file I am getting the following error from ms-word: "The file abc.docx cannot be opened because there are problems with contents". please help me to solve this problem.
#SuppressWarnings({ "unused", "static-access" })
#RequestMapping( value="/RegisterCandidate" , method = RequestMethod.POST)
private String RegisterCandidate(HttpServletRequest request,
HttpServletResponse response,
#RequestParam CommonsMultipartFile[] fileUpload ) throws Exception{
System.out.println("In method");
String email = request.getParameter("email");
System.out.println("email==============="+email);
String Password = request.getParameter("password");
String usr_name = request.getParameter("name");
String mobile_no = request.getParameter("mobile_no");
Date dateentry = new Date();
java.sql.Timestamp entry_date = new Timestamp(dateentry.getTime());
Users_Pojo usr = new Users_Pojo();
if (fileUpload != null && fileUpload.length > 0) {
for (CommonsMultipartFile aFile : fileUpload){
usr.setFilename(aFile.getOriginalFilename());
usr.setFile_data(aFile.getBytes());
System.out.println("aFile.getBytes()======"+aFile.getBytes());
System.out.println("aFile.getInputStream()======"+aFile.getInputStream());
System.out.println("aFile.getStorageDescription()======"+aFile.getStorageDescription());
System.out.println("aFile.getSize();======"+aFile.getSize());
System.out.println("aFile.getContentType();==="+aFile.getContentType());/* */
}
}
usr.setUc_password("ex123");
usr.setUc_name(email);
usr.setUc_contact_person(email);
usr.setUc_phone_no(BigInteger.valueOf(Long.parseLong(mobile_no)));
usr.setUc_email_id(email);
usr.setUc_type_id(1);
usr.setUc_active(1);
usr.setValid_from(null);
usr.setValid_to(null);
usr.setDesignation("jobseekar");
usr.setIp_address("164.100.200.179");
usr.setUser_location(1);
usr.setEntry_date(entry_date);
scm_service.save(usr, email);
/*System.out.println("email==="+email);
System.out.println("Password==="+Password);
System.out.println("usr filename==="+usr.getFilename());*/
return "success";
//return "redirect:Login.html";
}
Configuration:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2000000" />
</bean>
downloading using :
#RequestMapping(value = "/download",method = RequestMethod.GET)
public void getAttachmenFromDatabase( HttpServletRequest request,HttpServletResponse response){
response.setContentType("application/vnd.ms-word");
String resume_id = request.getParameter("resume_id");
long attachid = Long.parseLong(resume_id);
try {
Users_Pojo file_attachment = (Users_Pojo) scm_service.getFiles(attachid);
System.out.println("file_attachment.getFilename()======="+file_attachment.getFile_data());
response.setHeader("Content-Disposition", "inline; filename=\""+ file_attachment.getFilename() +"\"");
response.setContentLength(file_attachment.getFile_data().length);
FileCopyUtils.copy(file_attachment.getFile_data(), response.getOutputStream());
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
}
I have two servers - HelloServer and WorldServer.
Both implement the same proto file:
// The greeting service definition.
service GreeterService {
// Sends a greeting
rpc GreetWithHelloOrWorld (GreeterRequest) returns (GreeterReply) {}
rpc GreetWithHelloWorld (GreeterRequest) returns (GreeterReply) {}
}
message GreeterRequest {
string id = 1;
}
// The response message containing the greetings
message GreeterReply {
string message = 1;
string id = 2;
}
I want to add traceIds to the requests. As far as I understand, this is achieved through adding the traceId in the Metadata object.
Here is the test I am using to check that the traceIds are passed along. The request is made to the HelloServer which in turns calls the WorldServer and then finally returns the response.
#Test
public void greetHelloWorld() {
String traceId = UUID.randomUUID().toString();
Metadata metadata = new Metadata();
metadata.put(MetadataKeys.TRACE_ID_METADATA_KEY, traceId);
Greeter.GreeterRequest greeterRequest = Greeter.GreeterRequest.newBuilder().setId(traceId).build();
ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 8080)
.usePlaintext(true)
.build();
AtomicReference<Metadata> trailersCapture = new AtomicReference<>();
AtomicReference<Metadata> headersCapture = new AtomicReference<>();
ClientInterceptor clientInterceptor = MetadataUtils.newAttachHeadersInterceptor(metadata);
ClientInterceptor metadataCapturingClientInterceptor = MetadataUtils.newCaptureMetadataInterceptor(headersCapture, trailersCapture);
GreeterServiceBlockingStub blockingStub = GreeterServiceGrpc.newBlockingStub(ClientInterceptors.intercept(channel, clientInterceptor, metadataCapturingClientInterceptor));
GreeterServiceStub asyncStub = GreeterServiceGrpc.newStub(channel);
try {
Greeter.GreeterReply greeterReply = blockingStub.greetWithHelloWorld(greeterRequest);
String idInResponse = greeterReply.getId();
String idInHeaders = headersCapture.get().get(MetadataKeys.TRACE_ID_METADATA_KEY);
logger.info("Response from HelloService and WorldService -- , id = {}, headers = {}", greeterReply.getMessage(), idInResponse, idInHeaders);
assertEquals("Ids in response and header did not match", idInResponse, idInHeaders);
} catch (StatusRuntimeException e) {
logger.warn("Exception when calling HelloService and WorldService\n" + e);
fail();
} finally {
channel.shutdown();
}
}
Implementation of ServerInterceptor:
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
String traceId = headers.get(MetadataKeys.TRACE_ID_METADATA_KEY);
logger.info("objId=" + this.toString().substring(this.toString().lastIndexOf('#')) + " Trace id -- 1=" + headers.get(MetadataKeys.TRACE_ID_METADATA_KEY));
return next.startCall(new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
#Override
public void sendHeaders(Metadata headers) {
headers.put(MetadataKeys.TRACE_ID_METADATA_KEY, traceId);
logger.info("objId=" + this.toString().substring(this.toString().lastIndexOf('#')) + " Trace id -- 2 " + headers.get(MetadataKeys.TRACE_ID_METADATA_KEY));
super.sendHeaders(headers);
}
#Override
public void sendMessage(RespT message) {
logger.info("objId=" + this.toString().substring(this.toString().lastIndexOf('#')) + " message=" + message.toString());
super.sendMessage(message);
}
}, headers);
Here is the implementation of the greetWithHelloWorld() method:
public void greetWithHelloWorld(com.comcast.manitoba.world.hello.Greeter.GreeterRequest request,
io.grpc.stub.StreamObserver<com.comcast.manitoba.world.hello.Greeter.GreeterReply> responseObserver) {
Greeter.GreeterRequest greeterRequest = Greeter.GreeterRequest.newBuilder().setId(request.getId()).build();
Metadata metadata = new Metadata();
metadata.put(MetadataKeys.TRACE_ID_METADATA_KEY, "");
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8081)
.usePlaintext(true).build();
AtomicReference<Metadata> trailersCapture = new AtomicReference<>();
AtomicReference<Metadata> headersCapture = new AtomicReference<>();
ClientInterceptor clientInterceptor = MetadataUtils.newAttachHeadersInterceptor(metadata);
ClientInterceptor metadataCapturingClientInterceptor = MetadataUtils.newCaptureMetadataInterceptor(headersCapture, trailersCapture);
GreeterServiceGrpc.GreeterServiceBlockingStub blockingStub = GreeterServiceGrpc.newBlockingStub(ClientInterceptors.intercept(channel, clientInterceptor, metadataCapturingClientInterceptor));
String messageFromWorldService = "";
String replyIdFromWorldService = "";
try {
Greeter.GreeterReply greeterReply = blockingStub.greetWithHelloOrWorld(greeterRequest);
messageFromWorldService = greeterReply.getMessage();
replyIdFromWorldService = greeterReply.getId();
logger.info("Response from WorldService -- {}, id = {}", messageFromWorldService, replyIdFromWorldService);
} catch (StatusRuntimeException e) {
logger.warn("Exception when calling HelloService\n" + e);
}
Greeter.GreeterReply greeterReply = Greeter.GreeterReply.newBuilder().setMessage("Hello" + messageFromWorldService).setId(replyIdFromWorldService).build();
responseObserver.onNext(greeterReply);
responseObserver.onCompleted();
}
The problem is in the greetWithHelloWorld() method, I don't have access to Metadata, so I cannot extract the traceId from the header and attach it to the request to the World server. However, if I put a breakpoint in that method, I can see that request object does have the traceId in it which is private to it and unaccessible.
Any ideas how can I achieve this? Also, is this the best way to do pass traceIds around? I found some references to using Context. What is the difference between Context and Metadata?
The expected approach is to use a ClientInterceptor and ServerInterceptor. The client interceptor would copy from Context into Metadata. The server interceptor would copy from Metadata to Context. Use Contexts.interceptCall in the server interceptor to apply the Context all callbacks.
Metadata is for wire-level propagation. Context is for in-process propagation. Generally the application should not need to interact directly with Metadata (in Java).
I need to implement a list view containing a thumbnail, and this thumbnail is loaded using volley networkimageview. How would I implement this if my controller looks like this:
#RequestMapping (value="/rest/getphoto/", produces=MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte [] get Image (#RequestParam ("imageId"));
I've found many examples regarding the usage of volley but they are not helping me. Besides, I am using secure connection. Thanks in advance.
EDIT: I'm including controller code in my spring mvc project and the portion of code in my android client requesting an image.
* Spring MVC *
#RequestMapping(value = "/rest/singlephoto/", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte[] base64ImageForAndroid(#RequestParam("photoId") String photoIdParam, HttpServletRequest request)
{
String pathToLoad = "/path/default.png";
//HashMap<String, String> retVal = new HashMap<String, String>();
byte[] retVal;
try
{
long photoId = Long.parseLong(photoIdParam);
Photo photo = photoManager.getSinglePhoto(photoId);
if (photo != null)
pathToLoad = photo.getPath();
}
catch (NumberFormatException ex)
{
}
finally
{
try
{
File file = new File(pathToLoad);
retVal = FileUtils.readFileToByteArray(file);
}
catch (IOException ex)
{
retVal = null;
}
}
return retVal;
* Android Client Requesting with volley *
Bitmap thumb = imageCache.get(item.getThumbnailUrl() + "thumb");
if (thumb == null)
{
HttpHeaders headers = new HttpHeaders();
HttpBasicAuthentication auth = new HttpBasicAuthentication(this.username, this.password);
headers.setAuthorization(auth);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM));
Listener<byte[]> imageLoadedListener = new Response.Listener<byte[]>() {
#Override
public void onResponse(byte[] photoByteArray) {
Bitmap bitmap = EfficientImageLoading.decodeBitmapFromByteArray(photoByteArray, viewHolder.thumbnail.getWidth(), viewHolder.thumbnail.getHeight());
viewHolder.thumbnail.setImageBitmap(bitmap);
imageCache.put(item.getThumbnailUrl() + "thumb", bitmap);
//Cache full size and recycle
Bitmap fullBmp = EfficientImageLoading.decodeImageFromByteFullSize(photoByteArray);
imageCache.put(item.getThumbnailUrl(), fullBmp);
}
};
ErrorListener errorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
viewHolder.thumbnail.setImageResource(R.drawable.ic_launcher);
}
};
this.singleInstance.addToRequestQueue(new CustomImageRequest(Request.Method.GET, item.getThumbnailUrl(), errorListener, headers, imageLoadedListener));
}
Application server logs show:
GET /app//photo/rest/singlephoto/?photoId=7 HTTP/1.1" 406 1067
That is 406-- forbidden or something like that. Also android's LogCat shows an error like the following: BasicNetwork.PerformRequest: Unexpected response code 406 for https://domain/app/singlephoto?photoId=7
Is there something wrong with my controller or my client or both?
I read some articles about this and I find that to achive that wcf get data from post request we add
[ServiceContract]
public interface IService1 {
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/GetData")]
void GetData(Stream data);
}
and in implementation
public string GetData( Stream input)
{
long incomingLength = WebOperationContext.Current.IncomingRequest.ContentLength;
string[] result = new string[incomingLength];
int cnter = 0;
int arrayVal = -1;
do
{
if (arrayVal != -1) result[cnter++] = Convert.ToChar(arrayVal).ToString();
arrayVal = input.ReadByte();
} while (arrayVal != -1);
return incomingLength.ToString();
}
My question is what should I do that in submit action in form request will send to my service and consume?
In Stream parameter will I have post information from form to which I could get by Request["FirstName"]?
Your code isn't decoding the request body correctly - you're creating an array of string values, each one with one character. After getting the request body, you need to parse the query string (using HttpUtility is an easy way to do so). The code below shows how to get the body and one of the fields correctly.
public class StackOverflow_7228102
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/GetData")]
string GetData(Stream data);
}
public class Service : ITest
{
public string GetData(Stream input)
{
string body = new StreamReader(input).ReadToEnd();
NameValueCollection nvc = HttpUtility.ParseQueryString(body);
return nvc["FirstName"];
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
WebClient c = new WebClient();
c.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
Console.WriteLine(c.UploadString(baseAddress + "/GetData", "FirstName=John&LastName=Doe&Age=33"));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}