Below i have shared my code in detail. I read documentation and everything about handshake. I followed all the steps given in documentation and numerous examples on the internet but still i have this problem. Strange thing id websocket.onclsose() got triggered when I close the server.
// Simple Websocket server
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
namespace WebSocketServer
{
class Program
{
//port
private static int _port = 8181;
static void Main(string[] args)
{
TcpListener t = new TcpListener(IPAddress.Loopback, _port);
t.Start();
Console.WriteLine("Server is started and waiting for client\n\n");
byte[] buff = new byte[255];
NetworkStream stream;
TcpClient client;
while(true)
{
client = t.AcceptTcpClient();
if (!client.Connected)
return;
// I need form a proper mechanism to get all the data out of network stream.
// If I wait too long client get disconnected and we dont get stream and if
// if we dont wait at all then data doesnt reach server port and hence cant
// read the handshake.
stream = client.GetStream();
while ((stream.Read(buff, 0, buff.Length)) != 0)
{
break;
}
if (0 != buff.Length)
break;
}
StreamWriter writer = new StreamWriter(stream);
writer.AutoFlush = true;
//while (stream.DataAvailable)
//stream.Read(buff, 0, buff.Length);
Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(buff));
string clientHandshake = System.Text.ASCIIEncoding.ASCII.GetString(buff);
char[] separators = new char[1];
separators[0] = '\n';
string[] temp = clientHandshake.Split(separators, 100);
string keyword = "Sec-WebSocket-Key";
string key = "";
foreach (string s in temp)
{
if (s.Contains(keyword))
{
string keyTemp= s.Substring(keyword.Length + 2);
key = keyTemp.Remove(keyTemp.Length - 1);
break;
}
}
string responseKey = GetServerResponseKey(key);
// Send Server handshake
string handshake =
"HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n" +
"Sec-WebSocket-Accept: " + responseKey + "\r\n";
writer.Write(handshake);
writer.Flush();
Console.WriteLine(handshake);
while ((stream.Read(buff, 0, buff.Length)) != 0)
{
break;
}
Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(buff));
// Keep Server alive
while (true)
{ }
}
//Helper method to convert string into Byte[]
private static byte[] GetByteArray(string str)
{
UTF8Encoding encoding = new UTF8Encoding();
return encoding.GetBytes(str);
}
//This method is requuired because it combines key(got it from client)
//with GUID. Then takes SHA1 hash of that string and then encode to base64.
//This is all required because Handshake mechanism can be done by only this
//way according to Websocket Protocol(http://datatracker.ietf.org/doc/rfc6455/)
private static string GetServerResponseKey(string key)
{
Console.WriteLine("original key = " + key);
string keyForHash = String.Concat(key, Guid.NewGuid());
Console.WriteLine("text version of server response key = " + keyForHash);
UTF8Encoding encoding = new UTF8Encoding();
byte[] temp = encoding.GetBytes(keyForHash);
SHA1 hashProvider = new SHA1CryptoServiceProvider();
byte[] keyForBase64 = hashProvider.ComputeHash(temp);
return Convert.ToBase64String(keyForBase64);
}
}
}
// Simple WebSocket Client
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebSocketClient._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<script language="javascript" type = "text/javascript">
var ws;
function btnConnectSend_onclick() {
if ("WebSocket" in window) {
ws = new WebSocket("ws://localhost:8181");
ws.onopen = function() {
alert("Connection Open");
ws.send("Hello Server");
};
ws.onmessage = function(evt) {
form1.txtMessage.value = evt.data;
alert("Server says:" + evt.data);
};
ws.onclose = function() {
alert("Socket Closed!!!");
};
ws.onerror = function() {
alert("WTF!");
};
}
}
function btnClose_onclick() {
ws.close();
};
</script>
</head>
<body>
<form id="form1" runat="server">
<div style="height: 350px">
<input id="btnConnectSend" type="button" value="Connect/Send" onclick ="return btnConnectSend_onclick ()"/>
<br />
<input id="txtMessage" type="text"/>
<br />
<input id="btnClose" type="button" value="Close" onclick="return btnClose_onclick()"/>
</div>
</form>
</body>
</html>
I think you have a bug in GetServerResponseKey(). keyForHash should be assigned to String.Concat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
The value you append to the client's key must hard-coded and cannot be a dynamically generated guid. See pt 5 in section 4.2.2 of the spec.
Another point, you should consider checking the request for a Sec-WebSocket-Protocol header. If this is sent by the client, it'll expect you to echo the header in your handshake response (always assuming your server supports the sub-protocol of course). This won't cause a handshake to stall but may later cause the client to reject your handshake response.
Related
I have a WebService that is working and receiving files using the POST method, but in which I also need to receive data, simultaneously.
ASP.NET WebApi code:
public Task<HttpResponseMessage> Post()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var task = request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(o =>
{
string file1 = provider.FileData.First().LocalFileName;
return new HttpResponseMessage()
{
Content = new StringContent("File uploaded.")
};
}
);
return task;
}
And the client, developed for Android, is sending the file and the data like this (the send of the file is tested and working, the sending of the data is still not tested, as I need it to be working in the server side):
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Sample Text Content"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"file\"; filename=\"" + fileName + ".png\""),
RequestBody.create(MEDIA_TYPE_PNG, bitmapdata))
.addFormDataPart("fullpath", "test")
.build();
final com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder()
.url(url)
.post(requestBody)
.build();
How can I change the server to read not only the file but also the data?
Can any one help?
Thanks in advance.
The client in this case android is sending additional values in the body like media_type_png. I had to do something similar however the client was angular and not a mobile app, after some searching back then I found code from the following stackoverflow. Which resulted in the code below.
First receive the incoming message and check that you can process it i.e. [IsMimeMultipartContent][1]()
[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
// Here we just check if we can support this
if (!Request.Content.IsMimeMultipartContent())
{
this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
// This is where we unpack the values
var provider = new MultipartFormDataMemoryStreamProvider();
var result = await Request.Content.ReadAsMultipartAsync(provider);
// From the form data we can extract any additional information Here the DTO is any object you want to define
AttachmentInformationDto attachmentInformation = (AttachmentInformationDto)GetFormData(result);
// For each file uploaded
foreach (KeyValuePair<string, Stream> file in provider.FileStreams)
{
string fileName = file.Key;
// Read the data from the file
byte[] data = ReadFully(file.Value);
// Save the file or do something with it
}
}
I used this to unpack the data:
// Extracts Request FormatData as a strongly typed model
private object GetFormData(MultipartFormDataMemoryStreamProvider result)
{
if (result.FormData.HasKeys())
{
// Here you can read the keys sent in ie
result.FormData["your key"]
AttachmentInformationDto data = AttachmentInformationDto();
data.ContentType = Uri.UnescapeDataString(result.FormData["ContentType"]); // Additional Keys
data.Description = Uri.UnescapeDataString(result.FormData["Description"]); // Another example
data.Name = Uri.UnescapeDataString(result.FormData["Name"]); // Another example
if (result.FormData["attType"] != null)
{
data.AttachmentType = Uri.UnescapeDataString(result.FormData["attType"]);
}
return data;
}
return null;
}
The MultipartFormDataMemoryStreamProvider is defined as follows:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;
namespace YOURNAMESPACE
{
public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
private readonly Collection<bool> _isFormData = new Collection<bool>();
private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, Stream> _fileStreams = new Dictionary<string, Stream>();
public NameValueCollection FormData
{
get { return _formData; }
}
public Dictionary<string, Stream> FileStreams
{
get { return _fileStreams; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null)
{
throw new ArgumentNullException("parent");
}
if (headers == null)
{
throw new ArgumentNullException("headers");
}
var contentDisposition = headers.ContentDisposition;
if (contentDisposition == null)
{
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return base.GetStream(parent, headers);
}
public override async Task ExecutePostProcessingAsync()
{
for (var index = 0; index < Contents.Count; index++)
{
HttpContent formContent = Contents[index];
if (_isFormData[index])
{
// Field
string formFieldName = UnquoteToken(formContent.Headers.ContentDisposition.Name) ?? string.Empty;
string formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
else
{
// File
string fileName = UnquoteToken(formContent.Headers.ContentDisposition.FileName);
Stream stream = await formContent.ReadAsStreamAsync();
FileStreams.Add(fileName, stream);
}
}
}
private static string UnquoteToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
return token;
}
if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
{
return token.Substring(1, token.Length - 2);
}
return token;
}
}
}
I am working on a Spring-MVC application in which I have implemented chat functionality using Cometd. As a feature, I would like to know if there is any way Cometd has support or some way I can show which user is typing. Ofcourse the user information I can retrieve. Here is my chat code. Thanks.
ChatServiceImpl :
#Named
#Singleton
#Service
public class ChatServiceImpl {
#Inject
private BayeuxServer bayeux;
#Session
private ServerSession serverSession;
#Listener(value = "/service/person/{id}")
public void privateChat(ServerSession remote, ServerMessage.Mutable message,#Param("id")String id) {
System.out.println("wassup");
Person sender = this.personService.getCurrentlyAuthenticatedUser();
String senderName = sender.getFirstName();
Map<String, Object> input = message.getDataAsMap();
String data = (String) input.get("name");
String timestamp = (String) input.get("timestamp");
String temp = message.getChannel();
String temp1 = temp;
temp = temp.replace("/service/person/", "");
String channelName = temp1.replace("/service","");
final int conversationId = Integer.valueOf(temp);
Replies replies = new Replies();
replies.setReplyingPersonName(senderName);
replies.setReplyText(data);
replies.setReplyTimeStamp(timestamp);
replies.setReplyingPersonId(sender.getId());
replies.setRead(false);
Long replyId = this.repliesService.addReply(replies, conversationId, sender);
Map<String, Object> output = new HashMap<String, Object>();
output.put("text", data);
output.put("firstname", senderName);
output.put("channelname", channelName);
output.put("timestamp", timestamp);
output.put("id",sender.getId());
output.put("read","true");
output.put("replyid",replyId);
ServerChannel serverChannel = bayeux.createChannelIfAbsent("/person/" + id).getReference();
serverChannel.setPersistent(true);
serverChannel.publish(serverSession, output);
}
Application.js : Please note, I am using parts of this file in other JS file.
(function($)
{
var cometd = $.cometd;
$(document).ready(function()
{
function _connectionEstablished()
{
$('#body').append('<div>CometD Connection Established</div>');
}
function _connectionBroken()
{
$('#body').append('<div>CometD Connection Broken</div>');
}
function _connectionClosed()
{
$('#body').append('<div>CometD Connection Closed</div>');
}
var _connected = false;
function _metaConnect(message)
{
if (cometd.isDisconnected())
{
_connected = false;
_connectionClosed();
return;
}
var wasConnected = _connected;
_connected = message.successful === true;
if (!wasConnected && _connected)
{
_connectionEstablished();
}
else if (wasConnected && !_connected)
{
_connectionBroken();
}
}
// Function invoked when first contacting the server and
// when the server has lost the state of this client
function _metaHandshake(handshake)
{
if (handshake.successful === true)
{
cometd.batch(function()
{
cometd.subscribe('/chat/1306', function(message)
{
var data = message.data;
$('#body').append('<div>Server Says: ' + data.firstname + '/' + data.accountid + data.time1+'</div>');
});
});
}
}
// Disconnect when the page unloads
$(window).unload(function()
{
cometd.disconnect(true);
});
$(document).on('click', '#sender', function()
{
cometd.publish('/service/chat/1306', { name: 'hello_' + Date.now() });
});
var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
cometd.configure({
url: cometURL,
logLevel: 'debug'
});
cometd.websocketEnabled = false;
cometd.addListener('/meta/handshake', _metaHandshake);
cometd.addListener('/meta/connect', _metaConnect);
cometd.handshake();
});
})(jQuery);
Kindly let me know how I can achieve this, as I cannot find many references for this. Thanks a lot. :-)
This is easily achieved by detecting on the client side the typing start/stop (in a smart way to avoid to send too many messages to the server), then send a CometD service message to the server.
The server can then just broadcast a message to a special channel (say /chat/typing) with the nickname of the user that is typing.
The client application will subscribe to /chat/typing and receive these messages, then display in the UI who is typing, possibly coalescing multiple users into a single UI notification.
The CometD part is trivial, the detection of the start/stop of the typing in a smart way is probably most of the work.
I want to use Ajax for UserId validation, Can anyone help me out in connecting database?
Here is my JSP page .
enter code here
<script type="text/javascript">
/*
* creates a new XMLHttpRequest object which is the backbone of AJAX,
* or returns false if the browser doesn't support it
*/
function getXMLHttpRequest() {
var xmlHttpReq = false;
// to create XMLHttpRequest object in non-Microsoft browsers
if (window.XMLHttpRequest) {
xmlHttpReq = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
// to create XMLHttpRequest object in later versions
// of Internet Explorer
xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (exp1) {
try {
// to create XMLHttpRequest object in older versions
// of Internet Explorer
xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (exp2) {
xmlHttpReq = false;
}
}
}
return xmlHttpReq;
}
/*
* AJAX call starts with this function
*/
function makeRequest()
{
var c=document.getElementById("userid").value;
var xmlHttpRequest = getXMLHttpRequest();
xmlHttpRequest.onreadystatechange = getReadyStateHandler(xmlHttpRequest);
xmlHttpRequest.open("POST", "../userid", true);
xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form- urlencoded");
xmlHttpRequest.send("requestType=ajax&userid="+c);
}
/*
* Returns a function that waits for the state change in XMLHttpRequest
*/
function getReadyStateHandler(xmlHttpRequest) {
// an anonymous function returned
// it listens to the XMLHttpRequest instance
return function() {
if (xmlHttpRequest.readyState == 4) {
if (xmlHttpRequest.status == 200) {
document.getElementById("print").innerHTML = xmlHttpRequest.responseText;
} else {
alert("HTTP error " + xmlHttpRequest.status + ": " + xmlHttpRequest.statusText);
}
}
};
}
<form action="<%=application.getContextPath() %>/Login" method="post" name="myForm">
<table>
<tr>
<td>UserId</td>
<td><input type="text" name="userid" id="userid" onblur="makeRequest()" > </td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name="password" > </td>
</tr>
<tr><td></td>
<td><input type="submit" name="submit" value="Submit"></td>
<td><input type="hidden" name="requestType" value="Login"> </td>
</tr>
</table>
</form>
</script>
Please help me out for this. I require user id validation. If correct userid then it should display name, else display error msg.
To validate user:
Create a service/dao class with a method that interacts with database and returns boolean type.
create a Servlet and implement doPost() and use created service/dao class.
Finally, return true if user found, otherwise false in response.
In javascript display the message or error based on response from server.
for example:
create UserService class that will be look like:
public class UserService {
public Connection getConnection() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");//register database driver
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "****", "*****");
}
/**
* Checks a User id is exists in database using given user id<br/>
* <b>Note:</b> this method closes Connection and PreparedStatement you have passed as parameter
* #param pStatement A PreparedStatement instance with query to fetch result
* #return a true if user id found in database, else false returned.
*/
public boolean isUserExists(final String userId) {
if(userId==null || userId.isEmpty())
return false;
//declare required fields
Connection connection = null;
ResultSet rSet = null;
PreparedStatement pstmt = null;
boolean isExists = false; //set userId exists false initially
try{
connection = getConnection(); //get a connection to intract with database.
//create a PrepareStatement instance to fetch user id from database
pstmt = connection.prepareStatement("SELECT login FROM users WHERE login=?");
pstmt.setString(1, userId); // set user id which you want to retrieve from DB.
rSet = pstmt.executeQuery(); //execute the query
if(rSet.next()){ //check if you got any
System.out.printf("User id %s found",rSet.getString(1));
isExists = true; //user id exists, set true
}
}catch(SQLException e){
e.printStackTrace();
}finally{
//close all like: Connection, ResultSet and PreparedStatement etc
try { if (rSet != null) rSet.close(); } catch (Exception e) {};
try { if (pstmt != null) pstmt.close(); } catch (Exception e) {};
try { if (connection != null) connection.close(); } catch (Exception e) {};
}
return isExists;
}
}
and the Servlet will look like:
#WebServlet("/validateUserIdByAjax")
public class ValidateUserIdByAjax extends HttpServlet {
private static final long serialVersionUID = 1L;
private UserService userService = new UserService();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost() invoked..");
// Set response content type
response.setContentType("text/html");
// Set encoding
response.setCharacterEncoding("UTF-8");
//get user entered id
String userId = request.getParameter("userid");
//return userid status
response.getWriter().print(userService.isUserExists(userId));
}
}
Then, check response from server and show message in javascript like:
function getReadyStateHandler(xmlHttpRequest) {
// an anonymous function returned
// it listens to the XMLHttpRequest instance
return function() {
if (xmlHttpRequest.readyState == 4) {
if (xmlHttpRequest.status == 200) {
var $print = document.getElementById("print");
var res = xmlHttpRequest.responseText;
console.log('user status: '+res);
if(res=="true"){
$print.innerHTML = '<span style="color:red;">user id exists!</span>';
}else{
$print.innerHTML = '<span style="color:green;">user id available!</span>';
}
} else {
alert("HTTP error " + xmlHttpRequest.status + ": " + xmlHttpRequest.statusText);
}
}
};
}
that's it.
Note:
your AJAX POST url should match your Servlet url-patteren, in my case validateUserIdByAjax is the servlet url-pattern so AJAX url will look like:
xmlHttpRequest.open("POST", "validateUserIdByAjax", true);.
and Database driver class should be available in CLASSPATH, in my case i have used mySql so mysql-connector-java.jar is added to CLASSPATH.
In your question not have any element by id print, So please add to see the message while using above example,
like: <span id="print"></span>
make a jsp page with database connectivity that will be requested for output.....
in your ajax request send user_id and in jsp page get userid and check it from database ...if available then send true to ajax otherwise false.....
or in ajax response get message result from jsp page...make condition to handle this........
In my integration test the object schoolyearCreateRequest sent to /api/schoolyears url contains only null values when passing to the Post([FromBody] SchoolyearCreateRequest request) action parameter.
But when I use fiddler:
http://localhost:6320/api/schoolyears
Content-Type: application/json
Request Body:
{ SchoolyearDto:
{ Id: 10 }
}
Then it works and the SchoolyearDto is not null.
What is the problem in my integration test?
var schoolyearCreateRequest = new SchoolyearCreateRequest
{
SchoolyearDto = new SchoolyearDto(),
SchoolclassCodeDtos = new List<SchoolclassCodeDTO>(),
TimeTablesWeekAddedWeekA = new List<TimeTableDTO>(),
TimeTablesWeekAddedWeekAB = new List<TimeTableDTO>()
};
// Arrange
const string url = "api/schoolyears/";
var request = new HttpRequestMessage(HttpMethod.Post, _server.BaseAddress + url);
request.Content = new ObjectContent<SchoolyearCreateRequest>(schoolyearCreateRequest,new JsonMediaTypeFormatter());
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Act
var response = _client.PostAsync(_server.BaseAddress + url, request, new JsonMediaTypeFormatter(), new CancellationToken()).Result;
// Assert
Assert.That(response.StatusCode == HttpStatusCode.Created);
UPDATE:
I made it working now in my integration test too:
replace these lines:
request.Content = new ObjectContent<SchoolyearCreateRequest>(schoolyearCreateRequest,new JsonMediaTypeFormatter());
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
with this line:
var postData = new StringContent(JsonConvert.SerializeObject(schoolyearCreateRequest), Encoding.UTF8, "application/json");
Why do I have to serialize the data by myself? And why is nearly nobody doing this approach with web api integration testing? All blogs I read showed the usage of the ObjectContent ??
You can take a look at my answer in the following post:
How do I exercise Formatters in tests using HttpServer?
Also, you can take a look at my blog post which was written long time back, but is still relevant:
http://blogs.msdn.com/b/kiranchalla/archive/2012/05/06/in-memory-client-amp-host-and-integration-testing-of-your-web-api-service.aspx
UPDATE:
Since there seems to be confusion around this, following is a complete example of an in-memory test. Its a bit crude but still should give you an idea.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using WebApplication251.Models;
namespace WebApplication251.Tests.Controllers
{
[TestClass]
public class PeopleControllerTest
{
string baseAddress = "http://dummyhost/";
[TestMethod]
public void PostTest()
{
HttpConfiguration config = new HttpConfiguration();
// use the configuration that the web application has defined
WebApiConfig.Register(config);
HttpServer server = new HttpServer(config);
//create a client with a handler which makes sure to exercise the formatters
HttpClient client = new HttpClient(new InMemoryHttpContentSerializationHandler(server));
Person p = new Person() { Name = "John" };
using (HttpResponseMessage response = client.PostAsJsonAsync<Person>(baseAddress + "api/people", p).Result)
{
Assert.IsNotNull(response.Content);
Assert.IsNotNull(response.Content.Headers.ContentType);
Assert.AreEqual<string>("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
Person recPerson = response.Content.ReadAsAsync<Person>().Result;
Assert.AreEqual(p.Name, recPerson.Name);
}
}
}
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}
}
I have made this code for class but I just can't figure out why it is that when I click on a link, it won't show me the .jpg or .mp4 file. I've been scouring the Internet and I've tried converting the image from CMYK to RGB, adding even more CRLF to the end of the file and I simply can't understand why it gives me this error:
"The image cannot be displayed because it contains errors."
or
"The mp4 file cannot be displayed because it is corrupted"
This is my "welcome page"
<html>
<head>
<title> Welcome to my server</title>
</head>
<body bgcolor=white>
<p> Click one of the following: </p>
<p> Candy </p>
<p> Rossi vs Stoner </p>
</body>
</html>
And this is my server.
import java.io.*;
import java.net.Socket;
import java.util.*;
import java.awt.*;
import javax.imageio.*;
public class HTTPRequest implements Runnable
{
public static String CRLF = "\r\n"; // returning carriage return (CR) and a line feed (LF)
Socket socket;
// constructor
public HTTPRequest(Socket socket) throws Exception
{
this.socket = socket;
}
// Implement the run() method of the Runnable interface.
// Within run(), we explicitly catch and handle exceptions with a try/catch statement.
public void run()
{
try
{
processRequest();
} catch (Exception e)
{
System.out.println(e);
}
}
private void processRequest() throws Exception
{
//create an input and an output stream
InputStream instream = socket.getInputStream();
DataOutputStream outStream = new DataOutputStream(socket.getOutputStream());
// create a buffer
BufferedReader buffRead = new BufferedReader(new InputStreamReader(instream));// reads the input data
// Get the request line of the HTTP request message.
String requestLine = buffRead.readLine();// get /path/file.html version of http
// Display the request line.
System.out.println();
System.out.println(requestLine);
// HERE WE NEED TO DEAL WITH THE REQUEST
// Extract the filename from the request line.
StringTokenizer tokens = new StringTokenizer(requestLine);
tokens.nextToken();
String fileName = tokens.nextToken();
//this is so that i don't have to write /front.html at the start
if(fileName.equals("/")){
fileName="/front.html";
}
// attach a "." so that file request is within the current directory.
fileName = "." + fileName;
// Open the requested file.
FileInputStream fis = null;
boolean fileExists = true;
try
{
fis = new FileInputStream(fileName);
} catch (FileNotFoundException e)
{
fileExists = false;
}
// Construct the response message.
String statusLine = null;
String contentTypeLine = null;
String entityBody = null;
if (fileExists)
{
statusLine = "HTTP/1.0 200 OK" + CRLF; // 200 success code
contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
}// content info
else
{
contentTypeLine = "Content-type: text/html" + CRLF;// content info
entityBody = "<HTML>" + "<HEAD><TITLE>Not Found</TITLE></HEAD>"
+ "<BODY>Not Found</BODY></HTML>";
statusLine = "HTTP/1.0 404 Not Found" + CRLF;// 404 not found...
}
// Send the status line.
outStream.writeBytes(statusLine);
// Send the content type line.
outStream.writeBytes(contentTypeLine);
// Send a blank line to indicate the end of the header lines.
outStream.writeBytes(CRLF);
// Send the entity body.
if (fileExists)
{
outStream.writeBytes(statusLine);// Send the status line.
outStream.writeBytes("\n"+contentTypeLine);// Send the content type line.
sendBytes(fis, outStream);
fis.close();
} else
{
outStream.writeBytes(statusLine);// Send the status line
outStream.writeBytes("\n"+contentTypeLine);// Send the content type line.
outStream.writeBytes(entityBody);// Send the an html error message info body.
}
System.out.println("*****");
System.out.println(fileName);// print out file request to console
System.out.println("*****");
// Get and display the header lines.
String headerLine = null;
while ((headerLine = buffRead.readLine()).length() != 0)
{
System.out.println(headerLine);
}
// Close streams and socket.
outStream.close();
buffRead.close();
socket.close();
}
// return the file types
private static String contentType(String fileName)
{
if (fileName.endsWith(".htm") || fileName.endsWith(".html"))
{
return "text/html";
}
if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg"))
{
return "image/jpeg";
}
if (fileName.endsWith(".gif"))
{
return "image/gif";
}
if(fileName.endsWith(".mp4"))
{
return "movie";
}
return "application/octet-stream";
}
// set up i/o streams
private static void sendBytes(FileInputStream fis, DataOutputStream outStream)
throws Exception
{
// Construct a 1K buffer to hold bytes on their way to the socket.
byte[] buffer = new byte[1024];
int bytes = 0;
// Copy requested file into the socket's output stream.
while ((bytes = fis.read(buffer)) != -1)// read() returns minus one, indicating that the end of the file
{
outStream.write(buffer, 0, bytes);
outStream.writeBytes("\r\n");
}
}
}
Please help me. thank you.
i don't get this line :
outStream.writeBytes("\r\n");
anyway, could you dump the post so that we could check what's going on ?