I have written a socket program in C. I used this program as a chat server/client using TCP. I tried to change the chat server to use it as a HTTP server by changing the port to 80. I referred to the HTTP request/response format in http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Example_session , and made my program to reply with sample response. I tried the url
http://127.0.0.1/
in browser. My program read the request and replied with response. At first, I used google-chrome. Chrome didn't load the page correctly until i added the correct data length in Content-Length header. After setting content length header, chrome loaded the page correctly. But, firefox doesn't load the page. Firefox doesn't showed any errors, but still loading the page like it is still waiting for some data. Only When i stop the server or close the socket, complete page is loaded. I tried to follow rfc2616 https://www.rfc-editor.org/rfc/rfc2616 , and made the response exactly , but the still the results are same.
Request:
GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nUser-Agent: Mozilla/5.0
(X11; Ubuntu; Linux x86_64; rv:33.0) Gecko/20100101
Firefox/33.0\r\nAccept:
text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8\r\nAccept-Language:
en-US,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection:
keep-alive\r\n\r\n
For the above request, my program write to the socket with following response & content.
Response:
HTTP/1.1 200 OK\r\nCache-Control : no-cache, private\r\nContent-Length
: 107\r\nDate : Mon, 24 Nov 2014 10:21:21 GMT\r\n\r\n
Content:
<html><head><title></title></head><body>TIME : 1416824843 <br>DATE: Mon Nov 24 15:57:23 2014 </body></html>
This response is loading in Chrome, but not in firefox. Chrome is loading the page instantly whereas firefox is waiting for data. Note that the data length 107 is specified in the header. I donot have any addons enabled in firefox. My firefox version is in the request. Chrome version: Version 38.0.2125.111 (64-bit).
Code:
void *socket_read(void *args)
{
int socket,*s,length;
char buf[1024];
s=(int *)args;
socket=*s;
while(1){
buf[0]='\0';
length=read(socket,buf,1024);
if(length==0)
break;
else if(length==-1){
perror("Read");
return;
}
else{
printf("Request: %s\n",buf);
send_response(socket);
}
}
printf("End of read thread [%d]\n",socket);
}
int start_accept(int port)
{
int socket,csocket;
pthread_t thread;
struct sockaddr_in client;
socklen_t addrlen=sizeof(client);
pthread_attr_t attr;
socket=create_socket(port);
while(1){
if((csocket=accept(socket,(struct sockaddr *)&client,&addrlen))==-1)
{
perror("Accept");
break;
}
pthread_attr_init(&attr);
if(0!=pthread_create(&thread,&attr,socket_read,&csocket))
{
perror("Read thread");
return;
}
usleep(10000);
}
}
void send_response(int socket)
{
char buf1[1024];
int content_length;
char buf2[1024]="<html><head><title></title></head><body>TIME : 1416824843 <br>DATE: Mon Nov 24 15:57:23 2014 </body></html>";
content_length=strlen(buf2);
sprintf(buf1,"HTTP/1.1 200 OK\r\nCache-Control : no-cache, private\r\nContent-Length : %d\r\nDate : Mon, 24 Nov 2014 12:03:43 GMT\r\n\r\n",content_length);
printf("Written: %d \n",write(socket,buf1,strlen(buf1)));
fflush(stdout);
printf("Written: %d \n",write(socket,buf2,content_length));
fflush(stdout);
}
I have found the problem.
The Response is incorrect. There should not be any spaces between the header field name and colon(':'). Found this in http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 .
My correct response is
HTTP/1.1 200 OK\r\nCache-Control: no-cache, private\r\nContent-Length: 107\r\nDate: Mon, 24 Nov 2014 10:21:21 GMT\r\n\r\n
I had put a space between 'Content-Length' and ':' . That's the reason Firefox ignored the content length header and reading the socket. Chrome accepted the header fields with spaces, so the problem didn't occurred in chrome.
After removing the space, program works fine.
It actually loads the page. If you add content-type header you will see the HTML page (Content-Type: text/html; charset=UTF-8\r\n)
Anyway, both in Chrome and in Firefox you will see the connections never stops because the server doesn't close the socket. If you closed csocket, you would see the HTML page in both browsers but as you said it should be a persistent connection.
Related
I'm writing an HTTP server and client in python. When I run my scripts for client and server in terminal everything works fine. However, when I go to my browser and type "localhost:12000" in the searchbar, I get an error saying "The page isn't working. localhost didn't send any data. ERR_EMPTY_RESPONSE". What I expect to see instead, is the content of the html file contained in the response message.
This is the code for my HTTP client.
from socket import *
clientSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 18000
clientSocket.connect(("localhost",serverPort))
request = "GET www.somepage/index.html HTTP/1.0\r\nHost: www.somepage.com\r\nConnection: close\r\nUser-Agent: Chrome/86.0.4240.183\r\nAccept: text/html, application/xhtml+xml\r\nAccept-Language: it-IT, en-US\r\nAccept-Encoding: gzip, deflate\r\nAccept-Charset: ISO-8859-1, utf-8\r\n"
print(request)
clientSocket.send(request.encode())
response = (clientSocket.recv(1024)).decode()
print(response)
clientSocket.close()
This is the code for my server.
from socket import *
from datetime import date
from time import gmtime, strftime
import calendar
serverSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
serverSocket.bind(("localhost",serverPort))
serverSocket.listen(1)
current_date = calendar.day_abbr[date.today().weekday()]+", "+date.today().strftime("%d %b %Y")+strftime(" %H:%M:%S", gmtime())+ " GMT"
while True:
connection , addr = serverSocket.accept()
request = (connection.recv(1024)).decode()
request = request.split()
method = request[0]
URL = request[1]
version = request[2]
if method == "GET" and URL == "www.somepage/index.html" and version == "HTTP/1.0":
response = "HTTP/1.0 200 OK\r\nConnection: close\r\nDate: {}\r\nServer: Apache\r\nLast-Modified: Tue, 10 Nov 2020, 6:31:00 GMT\r\nContent-Length: 72 bytes\r\nContent-Type: text/html\r\n<html>\r\n<title>PAGE TITLE</title>\r\n<body>\rThis is the body\r\n</body></html>".format(current_date)
connection.send(response.encode())
connection.close()
So the server is checking if the request line is correct and then sending the HTTP response, which I do see in the terminal, but when I try in the browser I get an error instead. I've also tried checking Wireshark and I do see the HTTP messages there, so I don't understand why my browsers says no data has been sent.
Thank you all for your help.
Edit:
I couldn't post my code in the comment so I'll try here. What I'm trying to do is create an HTTP client and server than don't implement the entire HTTP protocol, but just a few request methods and a few replies. For now I was starting with the GET method and the 200 OK reply.
This is the code for my client. I have added an extra \r\n at the end of the header in the request.
from socket import *
clientSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
clientSocket.connect(("localhost",serverPort))
request = "GET /index.html HTTP/1.0 \r\nHost: www.somepage.com\r\nConnection: close\r\nUser-Agent: Chrome/86.0.4240.183\r\nAccept: text/html, application/xhtml+xml\r\nAccept-Language: it-IT, en-US\r\nAccept-Encoding: gzip, deflate\r\nAccept-Charset: ISO-8859-1, utf-8\r\n\r\n"
print(request)
clientSocket.send(request.encode())
response = (clientSocket.recv(1024)).decode()
print(response)
clientSocket.close()
This is the code for my server, with an added \r\n at the end of header as well.
from socket import *
from datetime import date
from time import gmtime, strftime
import calendar
serverSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
serverSocket.bind(("localhost",serverPort))
serverSocket.listen(1)
current_date = calendar.day_abbr[date.today().weekday()]+", "+date.today().strftime("%d %b %Y")+strftime(" %H:%M:%S", gmtime())+ " GMT"
while True:
connection , addr = serverSocket.accept()
request = (connection.recv(1024)).decode()
request = request.split()
method = request[0]
URI = request[1]
version = request[2]
host = request[4]
if method == "GET" and URI == "/index.html" and version == "HTTP/1.0" and host == "www.somepage.com":
response = "HTTP/1.0 200 OK \r\nConnection: close\r\nDate: {}\r\nServer: Apache\r\nLast-Modified: Tue, 10 Nov 2020, 6:31:00 GMT\r\nContent-Length: 83 bytes\r\nContent-Type: text/html\r\n\r\n<html>\r\n<title>PAGE TITLE</title>\r\n<body>\rThis is the body\r\n</body></html>".format(current_date)
connection.send(response.encode())
connection.close()
I've studied the standard and I'm trying to write my code according to the specifications. What I see in my browser is this error:
error
I've also noticed that if I change my server code to this:
from socket import *
from datetime import date
from time import gmtime, strftime
import calendar
serverSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
serverSocket.bind(("localhost",serverPort))
serverSocket.listen(1)
current_date = calendar.day_abbr[date.today().weekday()]+", "+date.today().strftime("%d %b %Y")+strftime(" %H:%M:%S", gmtime())+ " GMT"
while True:
connection , addr = serverSocket.accept()
request = (connection.recv(1024)).decode()
request = request.split()
method = request[0]
URI = request[1]
version = request[2]
host = request[4]
if "GET" in request:
response = "HTTP/1.0 200 OK \r\nConnection: close\r\nDate: {}\r\nServer: Apache\r\nLast-Modified: Tue, 10 Nov 2020, 6:31:00 GMT\r\nContent-Length: 83 bytes\r\nContent-Type: text/html\r\n\r\n<html>\r\n<title>PAGE TITLE</title>\r\n<body>\rThis is the body\r\n</body></html>".format(current_date)
connection.send(response.encode())
connection.close()
where basically the only difference is the way the if statement is written, then my browser will display correctly the html, that is, I see this:
page
So it seems the problem lies in the syntax I used for my python code, and not the way the standard is implemented?
Thank you again so very much for your help.
I couldn't post my code in the comment so I'll try here. What I'm trying to do is create an HTTP client and server than don't implement the entire HTTP protocol, but just a few request methods and a few replies. For now I was starting with the GET method and the 200 OK reply.
This is the code for my client. I have added an extra \r\n at the end of the header in the request.
from socket import *
clientSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
clientSocket.connect(("localhost",serverPort))
request = "GET /index.html HTTP/1.0 \r\nHost: www.somepage.com\r\nConnection: close\r\nUser-Agent: Chrome/86.0.4240.183\r\nAccept: text/html, application/xhtml+xml\r\nAccept-Language: it-IT, en-US\r\nAccept-Encoding: gzip, deflate\r\nAccept-Charset: ISO-8859-1, utf-8\r\n\r\n"
print(request)
clientSocket.send(request.encode())
response = (clientSocket.recv(1024)).decode()
print(response)
clientSocket.close()
This is the code for my server, with an added \r\n at the end of header as well.
from socket import *
from datetime import date
from time import gmtime, strftime
import calendar
serverSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
serverSocket.bind(("localhost",serverPort))
serverSocket.listen(1)
current_date = calendar.day_abbr[date.today().weekday()]+", "+date.today().strftime("%d %b %Y")+strftime(" %H:%M:%S", gmtime())+ " GMT"
while True:
connection , addr = serverSocket.accept()
request = (connection.recv(1024)).decode()
request = request.split()
method = request[0]
URI = request[1]
version = request[2]
host = request[4]
if method == "GET" and URI == "/index.html" and version == "HTTP/1.0" and host == "www.somepage.com":
response = "HTTP/1.0 200 OK \r\nConnection: close\r\nDate: {}\r\nServer: Apache\r\nLast-Modified: Tue, 10 Nov 2020, 6:31:00 GMT\r\nContent-Length: 83 bytes\r\nContent-Type: text/html\r\n\r\n<html>\r\n<title>PAGE TITLE</title>\r\n<body>\rThis is the body\r\n</body></html>".format(current_date)
connection.send(response.encode())
connection.close()
I've studied the standard and I'm trying to write my code according to the specifications. What I see in my browser is this error:
error
I've also noticed that if I change my server code to this:
from socket import *
from datetime import date
from time import gmtime, strftime
import calendar
serverSocket = socket(AF_INET,SOCK_STREAM)
serverPort = 12000
serverSocket.bind(("localhost",serverPort))
serverSocket.listen(1)
current_date = calendar.day_abbr[date.today().weekday()]+", "+date.today().strftime("%d %b %Y")+strftime(" %H:%M:%S", gmtime())+ " GMT"
while True:
connection , addr = serverSocket.accept()
request = (connection.recv(1024)).decode()
request = request.split()
method = request[0]
URI = request[1]
version = request[2]
host = request[4]
if "GET" in request:
response = "HTTP/1.0 200 OK \r\nConnection: close\r\nDate: {}\r\nServer: Apache\r\nLast-Modified: Tue, 10 Nov 2020, 6:31:00 GMT\r\nContent-Length: 83 bytes\r\nContent-Type: text/html\r\n\r\n<html>\r\n<title>PAGE TITLE</title>\r\n<body>\rThis is the body\r\n</body></html>".format(current_date)
connection.send(response.encode())
connection.close()
where basically the only difference is the way the if statement is written, then my browser will display correctly the html, that is, I see this:
page
So it seems the problem lies in the syntax I used for my python code, and not the way the standard is implemented?
Thank you again so very much for your help.
request = "GET www.somepage/index.html HTTP/1.0\r\nHost: www.somepage.com\r\nConnection: close\r\nUser-Agent: Chrome/86.0.4240.183\r\nAccept: text/html, application/xhtml+xml\r\nAccept-Language: it-IT, en-US\r\nAccept-Encoding: gzip, deflate\r\nAccept-Charset: ISO-8859-1, utf-8\r\n"
This is not a valid HTTP request. First, it should only contain the path /index.html and not domain/path as you currently do. It is also missing the final \r\n at the end which signals the end of the HTTP header.
In the same way the expectations of the server wrong too, which explains why it causes problems when faced with a client correctly implementing HTTP (the browser). Additionally the HTTP response is also missing the final \r\n after the HTTP header and the Content-length: 72 does not match the actual length of the content.
Please don't implement HTTP by (wrongly) second-guessing how it works. There is an actual standard for this and implementations are expected to follow this standard.
After the edit the code looks like this:
request = request.split()
...
version = request[2]
host = request[4]
if method == "GET" and URI == "/index.html" and version == "HTTP/1.0" and host == "www.somepage.com":
... send response ...
There are multiple problems here: the first one is that the browser will not use HTTP/1.0 as version but HTTP/1.1.
The next problem is that the domain might not be in the variable host since it is might not be in request[4]. It is blindly assumed that the Host header is in the second line of the request since it is implemented like this in the client. But the HTTP standard does in now way require this. And while it might be the case with some clients it is not the case with others. Instead of blindly assuming that something is in a specific place in the HTTP header the header should actually be parsed properly to extract the Host header.
I tried TFS 2015 REST API Authentication
However, it mentions request object (as I can't use javascript), not sure where is the request object or what type of it.
I am trying to pass query id and the code should execute the query and get result via API.
The solution works from my local, however, after publishing to server it does not seems working.
I also checked that the TFS is accessible from server using the credentials.
My code below:
private HttpClientHandler GetTfsCredentials()
{
HttpClientHandler handler2 = new HttpClientHandler { UseDefaultCredentials = true };
handler2.Credentials = new NetworkCredential("username", "password", "domain");
return handler2;
}
private async Task<object> GetQueryResults(string queryId)
{
string tfsApiUrl = ConfigurationManager.AppSettings["TfsApiUrl"];
string tfsProjectName = ConfigurationManager.AppSettings["TfsProjectName"];
string TfsProjectGuid = ConfigurationManager.AppSettings["TfsProjectGuid"];
//I tried both credentials and credentials2, but none of them working
string credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes($"{""}:{"password"}"));
string credentials2 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("domain\\username:password") );
if (!string.IsNullOrEmpty(tfsApiUrl) && !string.IsNullOrEmpty(tfsProjectName)
&& !string.IsNullOrEmpty(Id))
{
log.Info("GetQueryResults:: Config values found");
using (var client = new HttpClient(GetTfsCredentials()) { BaseAddress = new Uri(tfsApiUrl) })
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials2);
HttpResponseMessage response = client.GetAsync($"{tfsProjectName}/_apis/wit/wiql/{Id}").Result;
log.Info("GetQueryResults:: response.ReasonPhrase" + response.ReasonPhrase.ToString());
log.Info("GetQueryResults:: response" + response.ToString());
log.Info("GetQueryResults:: response.IsSuccessStatusCode" + response.IsSuccessStatusCode.ToString());
string workItemList = null;
if (response.IsSuccessStatusCode)
{
//do something
}
}
}
return null;
}
The error I received is:
2020-03-20 16:17:35,382 INFO GetQueryResults:: response.ReasonPhrase Unauthorized
2020-03-20 16:17:35,382 INFO GetQueryResults:: responseStatus Code: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
X-TFS-ProcessId: 115b5bba-0bf4-45e2-a3b2-2913ccc93f09
ActivityId: bb21d947-99a3-44dc-bdb7-317d7af34934
X-TFS-Session: bb21d947-99a3-44dc-bdb7-317d7af34934
X-VSS-E2EID: bb21d947-99a3-44dc-bdb7-317d7af34934
X-FRAME-OPTIONS: SAMEORIGIN
X-TFS-SoapException: %3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%3csoap%3aEnvelope+xmlns%3asoap%3d%22http%3a%2f%2fwww.w3.org%2f2003%2f05%2fsoap-envelope%22%3e%3csoap%3aBody%3e%3csoap%3aFault%3e%3csoap%3aCode%3e%3csoap%3aValue%3esoap%3aReceiver%3c%2fsoap%3aValue%3e%3csoap%3aSubcode%3e%3csoap%3aValue%3eUnauthorizedRequestException%3c%2fsoap%3aValue%3e%3c%2fsoap%3aSubcode%3e%3c%2fsoap%3aCode%3e%3csoap%3aReason%3e%3csoap%3aText+xml%3alang%3d%22en%22%3eTF400813%3a+The+user+%27CWOPA%5cSTCTCAPD006%24%27+is+not+authorized+to+access+this+resource.%3c%2fsoap%3aText%3e%3c%2fsoap%3aReason%3e%3c%2fsoap%3aFault%3e%3c%2fsoap%3aBody%3e%3c%2fsoap%3aEnvelope%3e
X-TFS-ServiceError: TF400813%3a+The+user+%27CWOPA%5cSTCTCAPD006%24%27+is+not+authorized+to+access+this+resource.
Server: Microsoft-IIS/8.5
WWW-Authenticate: Bearer
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
P3P: CP="CAO DSP COR ADMa DEV CONo TELo CUR PSA PSD TAI IVDo OUR SAMi BUS DEM NAV STA UNI COM INT PHY ONL FIN PUR LOC CNT"
Lfs-Authenticate: NTLM
X-Content-Type-Options: nosniff
Date: Fri, 20 Mar 2020 20:17:35 GMT
Content-Length: 82
Content-Type: text/plain; charset=utf-8
}
2020-03-20 16:17:35,382 INFO GetQueryResults:: response.IsSuccessStatusCode False
It looks like you are doing authentication in two different ways at once:
In the GetTfsCredentials-Method you set up Windows Authentication (NTLM or Kerberos)
By adding client.DefaultRequestHeaders.Authorization your try to set up Basic Authentication
Your TFS indicates (see WWW-Authenticate Header) that it supports Bearer, Negotiate and NTLM; but not Basic.
I would try:
Remove client.DefaultRequestHeaders.Authorization, credentials and credentials2. This should remove Basic-Authentication
Remove UseDefaultCredentials = true since you set explicit credentials the next line. UseDefaultCredentials tells HttpClientHandler to access TFS with the credentials of the running process, which is probably your account when executing locally and a service account when executing on the server.
Whithout this line, the specified NetworkCredential should be used to access TFS.
I have built a sample Citrus testcase to simulate a SOAP server that responds with an MTOM attachment.
runner.soap(action -> action.server("simulationServer")
.receive()
...[validation etc]
);
runner.soap(action -> action.server("simulationServer")
.send()
.name("get-response")
.mtomEnabled(Boolean.TRUE)
.attachment("myAttachment", "application/octet-stream", new ClassPathResource("testfiles/myAttachment.pdf"))
.payload("<getResponse xmlns:xmime=\"http://www.w3.org/2005/05/xmlmime\">\n" +
" <document>\n" +
" <contentElements>\n" +
" <contentElement xmime:contentType=\"application/pdf\">cid:myAttachment</contentElement>\n" +
" </contentElements>\n" +
" <id>Test</id>\n" +
" </document>\n" +
"</getResponse>\n")
);
When I run this test and call the Citrus simulation with SoapUI, I see the contents of myAttachment.pdf in the debug logs. So at least it looks like Citrus tries to send the attachment.
However, in SoapUI I do not get an attachment. There is a XOP element in the SOAP response, but no attachment. The RAW view of SoapUI of the Citrus response looks like this.
HTTP/1.1 200 OK
Date: Tue, 16 Jan 2018 15:30:36 GMT
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: Multipart/Related; boundary="----=_Part_0_382348859.1516116636524"; type="application/xop+xml"; start-info="text/xml"
Transfer-Encoding: chunked
Server: Jetty(9.4.6.v20170531)
------=_Part_0_382348859.1516116636524
Content-Type: application/xop+xml; charset=utf-8; type="text/xml"
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><getResponse xmlns:xmime="http://www.w3.org/2005/05/xmlmime">
<document>
<contentElements>
<contentElement xmime:contentType="application/pdf"><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myAttachment"/></contentElement>
</contentElements>
<id>Test</id>
</document>
</getResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
------=_Part_0_382348859.1516116636524--
In an MTOM response with attachment the attachment starts where this RAW view ends. It should continue like this
------=_Part_0_382348859.1516116636524-- [last line from above]
Content-Type: application/pdf
Content-Transfer-Encoding: binary
Content-ID: <myAttachment>
%PDF-1.4... [PDF content]
I am using Citrus 2.7.2 release.
Update
Still no success on this. Wireshark shows the same picture as SoapUI: the attachment is missing in the response.
However, when I debug into the code on the server (Citrus) side, I see the attachment in the response message until I get lost somewhere in a MessageSendingTemplate. Same on the console log. The message has the attachment.
There is an inline MTOM variant in the Citrus documentation, but I can't find a way to set this mtom-inline on the attachment in Java config.
Any hints, where to set a breakpoint to find where the attachment get lost? Or any other suggestions/examples on the Citrus side?
The setMtomInline field sits on the SoapAttachment interface. I am not sure if I got the setup right - but seems to work for inlined attachements - fails for soap attachements / multipart. The SoapUI Mock does not show any attachements when receiving requests from following testcase.
SoapAttachment soapAttachment = new SoapAttachment();
soapAttachment.setMtomInline(false);
soapAttachment.setContentResourcePath("log4j.xml");
soapAttachment.setContentType("application/octet-stream");
soapAttachment.setContentId("FILE");
SoapMessage soapMessage = new SoapMessage();
soapMessage.mtomEnabled(true);
soapMessage.soapAction("/HelloService/sayHello");
soapMessage.setPayload(
"<ht:HelloRequest " +
"xmlns:ht=\"http://citrusframework.org/schemas/samples/HelloMtomService\" " +
"xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" >\n" +
" <ht:Message>Hei .. citrus does stream mtom</ht:Message>\n" +
" <ht:Data><xop:Include href=\"cid:FILE\"/></ht:Data>\n" +
"</ht:HelloRequest>");
soapMessage.addAttachment(soapAttachment);
runner.soap(action -> {
action.client("helloMtomSoapuiClient")
.send()
.soapAction("/HelloService/sayHello")
.message(soapMessage);
});
If I do the same for MtomInline set to true, I see the attachement as base64 encoded content text in the ht:Data node.
SoapAttachment soapAttachment = new SoapAttachment();
soapAttachment.setContentResourcePath("log4j.xml");
soapAttachment.setMtomInline(true);
soapAttachment.setContentType("application/xml");
soapAttachment.setContentId("MyAttachement");
soapAttachment.setEncodingType("base64Binary");
runner.soap(action -> {
action.client("helloMtomSoapuiClient")
.send()
.soapAction("/HelloService/sayHello")
.mtomEnabled(true)
.payload("<ht:HelloRequest xmlns:ht=\"http://citrusframework.org/schemas/samples/HelloMtomService\">\n" +
" <ht:Message>Hei .. citrus does mtom</ht:Message>\n" +
" <ht:Data>cid:MyAttachement</ht:Data>\n" +
"</ht:HelloRequest>")
.attachment(soapAttachment);
});
Either soapUI or citrus swallows the attachement. Some help or working JavaDSL sample would be nice.
It was actually a bug that will be fixed in Citrus 2.7.4 release. See https://github.com/christophd/citrus/issues/328
The inline MTOM variant with XML config works for me in the current release.
<ws:send endpoint="simulationServer" mtom-enabled="true">
<message>
<resource file="testfiles/simulation/get-response.xml" />
</message>
<ws:attachment content-id="myAttachment" content-type="application/octet-stream" mtom-inline="true" encoding-type="base64Binary">
<ws:resource file="classpath:testfiles/myAttachment.pdf"/>
</ws:attachment>
</ws:send>
Trying to consume Azure media service rest api. (following the tutorial : https://learn.microsoft.com/en-us/azure/media-services/media-services-rest-get-started)
Everything works fine until the point I try to create a Job. Sending the same request as in example (except asset id and token) and getting response :
Parsing request content failed due to: Make sure to only use property names that are defined by the type
Request:
POST https://wamsdubclus001rest-hs.cloudapp.net/api/Jobs HTTP/1.1
Connection: Keep-Alive
Content-Type: application/json
Accept: application/json; odata=verbose
Accept-Charset: UTF-8
Authorization: Bearer token -> here i send real token
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
x-ms-version: 2.11
Content-Length: 458
Host: wamsdubclus001rest-hs.cloudapp.net
{
"Name":"TestJob",
"InputMediaAssets":[
{
"__metadata":{
"uri":"https://wamsdubclus001rest-hs.cloudapp.net/api/Assets('nb%3Acid%3AUUID%3A5168b52a-68ed-4df1-bac8-0648ce734ff6')"
}
}
],
"Tasks":[
{
"Configuration":"Adaptive Streaming",
"MediaProcessorId":"nb:mpid:UUID:ff4df607-d419-42f0-bc17-a481b1331e56",
"TaskBody":"<?xml version=\"1.0\" encoding=\"utf-8\"?><taskBody><inputAsset>JobInputAsset(0)</inputAsset> <outputAsset>JobOutputAsset(0)</outputAsset></taskBody>"
}
]
}
Response:
{
"error":{
"code":"",
"message":{
"lang":"en-US",
"value":"Parsing request content failed due to: Make sure to only use property names that are defined by the type"
}
}
}
It seems to be related with __metadata property. when I follow instruction from here : Creating Job from REST API returns a request property name error, the error changes:
"error":{
"code":"",
"message":{
"lang":"en-US",
"value":"Invalid input asset reference in TaskBody - "
}
}
}
Cant figure out whats wrong, thanks
Let me check on this, but it could be a couple issues that I have run into in the past.
First. Set both the Accept and Content-Type headers to:
"application/json; odata=verbose"
Next, double check that you are actually using the long underscore character on the metadata property. I've had issues where that was sending the wrong underscore character and it didn't match the property name.
Let me know if either of those helps.
It seems the issue was about "Content-Type". As I am using .net Core it was not easy to set the Conent-type as "application/json; odata=verbose".
1) Tried with RestSharp - dosnt support it, it cuts "odata=verbose" part out
2) Tried with Systsem.Net.Http.HttpClient -> Possible but difficult.
To add it as "Accept" :
MediaTypeWithQualityHeaderValue mtqhv;
MediaTypeWithQualityHeaderValue.TryParse("application/json;odata=verbose", out mtqhv);
client.DefaultRequestHeaders.Accept.Add(mtqhv);//ACCEPT header
To add it as "Content-Type" :
request.Content = new StringContent(content,
System.Text.Encoding.UTF8); //CONTENT-TYPE header -> default type will be text/html
request.Content.Headers.Clear(); // need to clear it - it will fail otherwise
request.Content.Headers.TryAddWithoutValidation("Content-Type","application/json;odata=verbose");
For a little fun I wanted to make a simple HTTP request in Rust. I threw this together and it works great:
use std::io::TcpStream;
fn main() {
// This just does a "GET /" to www.stroustrup.com
println!("Establishing connection...");
let mut stream = TcpStream::connect("www.stroustrup.com:80").unwrap();
println!("Writing HTTP request...");
// unwrap() the result to make sure it succeeded, at least
let _ = stream.write(b"GET / HTTP/1.1\r\n\
Host: www.stroustrup.com\r\n\
Accept: */*\r\n\
Connection: close\r\n\r\n").unwrap();
println!("Reading response...");
let response = stream.read_to_string().unwrap();
println!("Printing response:");
println!("{}", response);
}
Response is:
Establishing connection...
Writing HTTP request...
Reading response...
Printing response:
HTTP/1.1 200 OK
...and the rest of the long HTTP response with all the HTML as I'd expect...
However, if I change the request to be /C++.html instead of /:
use std::io::TcpStream;
fn main() {
// The only change is to "GET /C++.html" instead of "GET /"
println!("Establishing connection...");
let mut stream = TcpStream::connect("www.stroustrup.com:80").unwrap();
println!("Writing HTTP request...");
// unwrap() the result to make sure it succeeded, at least
let _ = stream.write(b"GET /C++.html HTTP/1.1\r\n\
Host: www.stroustrup.com\r\n\
Accept: */*\r\n\
Connection: close\r\n\r\n").unwrap();
println!("Reading response...");
let response = stream.read_to_string().unwrap();
println!("Printing response:");
println!("{}", response);
}
The socket returns "invalid input":
Establishing connection...
Writing HTTP request...
Reading response...
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: invalid input', /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/libcore/result.rs:746
Why does the socket return "invalid input"? The TCP socket isn't aware of the HTTP protocol (and I've tested my request with telnet and netcat: it's correct), so it can't be complaining about HTTP request/response.
What does "invalid input" even mean here? Why doesn't this work?
My rust version (I'm on OS X 10.10.1):
$ rustc --version
rustc 1.0.0-nightly (ea6f65c5f 2015-01-06 19:47:08 +0000)
The "invalid input" error isn't coming from the socket. It's coming from String. If the read_to_string() call is changed to read_to_end(), then the response is successful. Apparently the response isn't valid UTF-8.
More explicitly, the code:
println!("Reading response...");
let response = stream.read_to_end().unwrap();
println!("Printing response:");
println!("{}", String::from_utf8(response));
returns:
Err(invalid utf-8: invalid byte at index 14787)
So the HTTP response is bad. Looking at the web page, the error is here (the � characters are the problem):
Lang.Next'14 Keynote: What � if anything � have we learned from C++?
The offending characters are 0x96, indeed invalid utf-8. It should be U+2013 –
The document is either iso-8859-1 or windows 1252. There are a number of other problems with that HTML, such as unescaped &'s.