How to allow encoded slashes for websockets in tomcat? - java

Is there a way to enable encoded slashes for websockets in tomcat?
I have set org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH to true and it works as expected for web requests.
Hovewer, there is a problem with WS requests. That setting doesn't seem to work for them.
I have WS endpoint configured as like this:
#ServerEndpoint(value = "/ws/data/{path}", decoders = ChatMessageDecoder.class, encoders = ChatMessageEncoder.class)
It works just fine for URL ws://localhost:8080/app/ws/data/Test but it doesn't work for URL ws://localhost:8080/ws/data/Test%2FSubDir. For the latter URL I receive 404 error.
Is there a way to allow encoded slashes for WS requests?

Maybe you are ignoring the #PathParam.
I tried the following code and works as expected without any additional configuration:
package com.logicbig.example;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import javax.websocket.server.PathParam;
#ServerEndpoint("/hello/{parameter}")
public class HelloWorldEndpointWilcard {
public HelloWorldEndpointWilcard() {
System.out.println("class loaded " + this.getClass());
}
#OnOpen
public void onOpen(Session session, #PathParam("parameter") String parameter) {
System.out.printf("Session opened, id: %s%n", session.getId());
System.out.println("parameter onOpen:"+parameter);
try {
session.getBasicRemote().sendText("Hi there, we are successfully connected.");
} catch (IOException ex) {
ex.printStackTrace();
}
}
#OnMessage
public void onMessage(String message, Session session, #PathParam("parameter") String parameter) {
System.out.printf("Message received. Session id: %s Message: %s%n",
session.getId(), message);
System.out.println("parameter onMessage:"+parameter);
try {
session.getBasicRemote().sendText(String.format("We received your message: %s%n", message));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#OnError
public void onError(Throwable e) {
e.printStackTrace();
}
#OnClose
public void onClose(Session session) {
System.out.printf("Session closed with id: %s%n", session.getId());
}
}
And this javascript client:
var webSocket = new WebSocket("ws://localhost:8080/example/hello/Test%2FSubDir");
Test%2FSubDir value was received successfully on session established and on each message:
Complete java source code here

I couldn't make encoding working, but I have 3 alternative solutions.
Make multiple #ServerEndpoint:
#ServerEndpoint(value = "/ws/data/{path}"
public SingleChatHandler : ChatHandler {
#OnOpen
public void onOpen(
Session session,
#PathParam("path") String path) {
onOpenInternal(session, path);
}
}
#ServerEndpoint(value = "/ws/data/{path1}/{path2}"
public DoubleChatHandler : ChatHandler {
#OnOpen
public void onOpen(
Session session,
#PathParam("path1") String path1,
#PathParam("path2") String path2) {
onOpenInternal(session, path1 + '/' + path2);
}
}
public abstract class ChatHandler {
protected void onOpenInternal(Session session, String path) { [...] }
}
This however has two main disadvantages:
depth of the path must be know beforehand to implement required handlers
there is no way to have more than one parameter with slashes
Use query string instead of #PathParam:
#ServerEndpoint(value = "/ws/data")
public class ChatHandler {
#OnOpen
public void onOpen(Session session) {
Map<String, List<String>> map = session.getRequestParameterMap();
if (!map.containsKey("path")) {
// TODO: throw exception
}
String path = map.get("path").get(0);
}
}
This has 2 disadvantages as well, but less troublesome:
URL is not too nice
there will be no 404 when parameters are not provided (I still see 101)
Use query string instead of #PathParam (use code from 2. as a base) and check query string in modifyHandshake method:
public class ChatHandlerConfigurator extends ServerEndpointConfig.Configurator
{
#Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response)
{
Map<String, List<String>> map = request.getParameterMap();
if (!map.containsKey("path")) {
throw new IllegalArgumentException("path was not provided");
}
// Optionally add values to userProperties
Map<String, Object> userProperties = config.getUserProperties();
userProperties.put("path", map.get("path").get(0));
}
}
This behaves similarly to 2. but since I throw exception on handshake, instead of 101 there will be 500 error.

Related

Disconnect Websocket on server side based on a token passed from UI

My aim is to connect browser clients having proper headers with the server. I pass these headers from StompClient.
My UI code in which i passed token in the header is
function connect() {
var socket = new SockJS('/websocket/api/add');
stompClient = Stomp.over(socket);
stompClient.connect({"token" : "12345"}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
});
}
In backend i am able to read the headers in the preSend() method of ChannelInterceptorAdapter
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
MessageHeaders headers = message.getHeaders();
System.out.println("preSend : HEADERS : {}" + headers);
return super.preSend(message, channel);
}
But here i am not able to close the wesocket session. How can we do that?
Also i was able to close the websocket session but i couldn't receive the headers in afterConnectionEstablished() method of WebSocketHandlerDecorator
public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
session.close(CloseStatus.NOT_ACCEPTABLE);
super.afterConnectionEstablished(session);
}
};
}
});
super.configureWebSocketTransport(registration);
}
Can someone guide me how can i close the websocketsession based on the header we pass from UI at server side?
You can try sending the client's token to the server through a message when connection established, then let the server save that session into a map, whose key is the corresponding token.
So when you want to close a session by its token, you can query for the session from that map using the token.
Sample Code:
Save the session with its token:
#Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
String messageToString = message.getPayload().toString();
if (messageToString.startsWith("token=")) {
tokenToSessionMapping.put(messageToString.substring("token=".length()));
}
// Other handling message code...
}
Close the session by token:
WebSocketSession sessionByToken = tokenToSessionMapping.get(token);
if (sessionByToken != null && sessionByToken.isOpen()) {
sessionByToken.close(CloseStatus.NOT_ACCEPTABLE);
}
And other things to notice:
Since the tokenToSessionMapping is static and is shared among sessions. You should use a thread-safe implementation such as ConcurrentHashMap.
When the session is closed, you'd better remove the corresponding entry from the map tokenToSessionMapping. Otherwise the map size will just keep growing. You can do this by the override method afterConnectionClosed().
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Log.info("Socket session closed: {}", status.toString());
String foundKey = null;
for (Map.Entry<String, String> entry : tokenToSessionMapping.entrySet()) {
if (Objects.equals(entry.getValue(), session)) {
foundKey = entry.getKey();
}
}
if (foundKey != null) {
tokenToSessionMapping.remove(foundKey);
}
}

spring tcp socket , authorizing clients and handle pending response

The Spring framework support tcp connection as well , i wrote code below to setup a simple socket server , i am confused about adding below futures to my socket server :
authorizing clients based on a unique identifier ( for example a client secret received from client, maybe using TCP Connection Events )
send a message directly to specific client (based on identifier)
broadcast a message
UPDATE :
Config.sendMessage added to send message to single client
Config.broadCast added to broadcast message
authorizeIncomingConnection to authorize clients , accept or reject connections
tcpConnections static filed added to keep tcpEvent sources
Questions !
is using tcpConnections HashMap good idea ?!
is the authorization method i implemented a good one ?!
Main.java
#SpringBootApplication
public class Main {
public static void main(final String[] args) {
SpringApplication.run(Main.class, args);
}
}
Config.java
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class Config implements ApplicationListener<TcpConnectionEvent> {
private static final Logger LOGGER = Logger.getLogger(Config.class.getName());
#Bean
public AbstractServerConnectionFactory AbstractServerConnectionFactory() {
return new TcpNetServerConnectionFactory(8181);
}
#Bean
public TcpInboundGateway TcpInboundGateway(AbstractServerConnectionFactory connectionFactory) {
TcpInboundGateway inGate = new TcpInboundGateway();
inGate.setConnectionFactory(connectionFactory);
inGate.setRequestChannel(getMessageChannel());
return inGate;
}
#Bean
public MessageChannel getMessageChannel() {
return new DirectChannel();
}
#MessageEndpoint
public class Echo {
#Transformer(inputChannel = "getMessageChannel")
public String convert(byte[] bytes) throws Exception {
return new String(bytes);
}
}
private static ConcurrentHashMap<String, TcpConnection> tcpConnections = new ConcurrentHashMap<>();
#Override
public void onApplicationEvent(TcpConnectionEvent tcpEvent) {
TcpConnection source = (TcpConnection) tcpEvent.getSource();
if (tcpEvent instanceof TcpConnectionOpenEvent) {
LOGGER.info("Socket Opened " + source.getConnectionId());
tcpConnections.put(tcpEvent.getConnectionId(), source);
if (!authorizeIncomingConnection(source.getSocketInfo())) {
LOGGER.warn("Socket Rejected " + source.getConnectionId());
source.close();
}
} else if (tcpEvent instanceof TcpConnectionCloseEvent) {
LOGGER.info("Socket Closed " + source.getConnectionId());
tcpConnections.remove(source.getConnectionId());
}
}
private boolean authorizeIncomingConnection(SocketInfo socketInfo) {
//Authorization Logic , Like Ip,Mac Address WhiteList or anyThing else !
return (System.currentTimeMillis() / 1000) % 2 == 0;
}
public static String broadCast(String message) {
Set<String> connectionIds = tcpConnections.keySet();
int successCounter = 0;
int FailureCounter = 0;
for (String connectionId : connectionIds) {
try {
sendMessage(connectionId, message);
successCounter++;
} catch (Exception e) {
FailureCounter++;
}
}
return "BroadCast Result , Success : " + successCounter + " Failure : " + FailureCounter;
}
public static void sendMessage(String connectionId, final String message) throws Exception {
tcpConnections.get(connectionId).send(new Message<String>() {
#Override
public String getPayload() {
return message;
}
#Override
public MessageHeaders getHeaders() {
return null;
}
});
}
}
MainController.java
#Controller
public class MainController {
#RequestMapping("/notify/{connectionId}/{message}")
#ResponseBody
public String home(#PathVariable String connectionId, #PathVariable String message) {
try {
Config.sendMessage(connectionId, message);
return "Client Notified !";
} catch (Exception e) {
return "Failed To Notify Client , cause : \n " + e.toString();
}
}
#RequestMapping("/broadCast/{message}")
#ResponseBody
public String home(#PathVariable String message) {
return Config.broadCast(message);
}
}
Usage :
Socket Request/Response Mode
notify single client
http://localhost:8080/notify/{connectionId}/{message}
broadCast
http://localhost:8080/broadCast/{message}
The TcpConnectionOpenEvent contains a connectionId property. Each message coming from that client will have the same property in the IpHeaders.CONNECTION_ID message header.
Add a custom router that keeps track of the logged-on state of each connection.
Lookup the connection id and if not authenticated, route to a challenge/response subflow.
When authenticated, route to the normal flow.
To use arbitrary messaging (rather than request/response) use a TcpReceivingChannelAdapter and TcpSendingMessageHandler instead of an inbound gateway. Both configured to use the same connection factory. For each message sent to the message handler, add the IpHeaders.CONNECTION_ID header to target the specific client.
To broadcast, send a message for each connection id.

Simple websocket and static file example

Trying to set up undertwo to play with it a bit, i am trying to server a static html file index.html and add my annoted websocket ServerEndpoint pojo so i did the following
final Xnio xnio = Xnio.getInstance("nio", Undertow.class.getClassLoader());
final XnioWorker xnioWorker = xnio.createWorker(OptionMap.builder().getMap());
WebSocketDeploymentInfo webSockets = new WebSocketDeploymentInfo ()
.addEndpoint(Socket.class)
.setWorker(xnioWorker);
final DeploymentManager deployment = defaultContainer()
.addDeployment(deployment()
.setClassLoader(main.class.getClassLoader())
.setContextPath("/websockets")
.setDeploymentName("websockets")
.addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, webSockets));
deployment.deploy();
deployment.start();
Undertow.builder()
.addHttpListener(8000,"localhost")
.setHandler(path().addPrefixPath("/", resource(new ClassPathResourceManager(main.class.getClassLoader(), main.class.getPackage())).addWelcomeFiles("WSGSS/index.html")))
.build()
.start();
the index.html gets served as expected but i cant seem to connect to the websocket, and i am sure i am doing something wrong with the way i deploy the websocket, if i do it as in the examples on github it works but then i cant find the right way to serve the static files
in javascript i get the exception
var ws = new WebSocket("ws://localhost:8000/websockets/socket")
WebSocket connection to 'ws://localhost:8000/websockets/socket' failed: Error during WebSocket handshake: Unexpected response code: 404
also here is my ServerEndpoint
#ServerEndpoint(value = "/socket",
encoders = CommandEncoder.class,
decoders = CommandDecoder.class)
public class Socket{
private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());
private final Logger log = Logger.getLogger(getClass().getName());
#OnMessage
public void onMessage(Session session,Command command){
log.info("command of type "+ command.getAction() + " recieved");
command.Process();
try{
session.getBasicRemote().sendObject(command);
//Future<Void> future = session.getAsyncRemote().sendText(message);
} catch (IOException | EncodeException ex){
log.info(ex.getMessage() + ex.getCause());
}
}
#OnOpen
public void onOpen(Session session){
sessions.add(session);
log.info("new session created "+ session.getId());
}
#OnClose
public void onClose(Session session){
sessions.remove(session);
}
#OnError void onError(Session session,Throwable thr){
log.info(session.getId() + " error " + thr.getMessage() + thr.getCause());
}
}
The following solves it
Undertow.builder()
.addHttpListener(8000,"localhost")
.setHandler(path()
.addPrefixPath("/", resource(new ClassPathResourceManager(main.class.getClassLoader(), main.class.getPackage())).addWelcomeFiles("WSGSS/index.html"))
.addPrefixPath("/websocket",manager.deployment()))
.build()
.start();

Handling MaxUploadSizeExceededException can not stop uploading file

I want to check size of uploading files and prevent files loaded in memory entirely. I'm using CommonsMultipartFile. The uploaded file will be processed and persisted in DB. AbstractCoupleUploadController class handles incoming request that containing files:
public abstract class AbstractCoupleUploadController<T extends Serializable> extends RemoteServiceServlet implements ServletContextAware,
UploadServlet<WorkshopHistoryModel>
{
...
#RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
public ModelAndView handleRequest(#RequestParam("firstFile") CommonsMultipartFile firstFile,
#RequestParam("secondFile") CommonsMultipartFile secondFile, HttpServletRequest request, HttpServletResponse response)
{
synchronized(this)
{
initThreads();
perThreadRequest.set(request);
perThreadResponse.set(response);
}
handleUpload(firstFile,secondFile,request,response);
response.getWriter().flush();
response.flushBuffer();
return null;
}
private void handleUpload(CommonsMultipartFile firstFile, CommonsMultipartFile secondFile, HttpServletRequest request,
HttpServletResponse response) throws IOException
{
response.setContentType("text/html");
if(firstFile.getSize() == 0 || secondFile.getSize() == 0)
{
response.getWriter().print(AppConstants.UPLOAD_ZERO_SIZE_FILE);
return;
}
// other validations
// uploading:
try
{
String content = request.getParameter(CoupleUploadPanel.CONTENT);
T model = deserialize(content);
UploadResultModel resultModel = upload(model,firstFile,secondFile); // it's implemented in UploadFileServletImpl
if(resultModel.hasCriticalError())
{
response.getWriter().print(AppConstants.UPLOAD_FAIL + "," + String.valueOf(resultModel.getWorkshopHistoryId()));
}
else
{
response.getWriter().print(AppConstants.UPLOAD_SUCCESS + "," + String.valueOf(resultModel.getWorkshopHistoryId()));
}
}
catch(ProcessRequestException e)
{
// write upload error description in response.getWriter()
}
catch(Exception e)
{
e.printStackTrace();
response.getWriter().print(AppConstants.UPLOAD_UNKOWN_ERROR);
}
}
...
}
I have a multipartResolver bean in my app-servlet.xml (file.upload.max_size=9437184), And also a maxUploadSizeExceededExceptionHandler bean for handling UploadSizeExceededExceptions:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="${file.upload.max_size}" />
</bean>
<bean id="maxUploadSizeExceededExceptionHandler" class="com.insurance.ui.server.uploadfile.MaxUploadSizeExceededExceptionHandler">
<property name="order" value="1"/>
</bean>
My maxUploadSizeExceededExceptionHandler:
public class MaxUploadSizeExceededExceptionHandler implements HandlerExceptionResolver, Ordered
{
private int order;
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
{
if(ex instanceof MaxUploadSizeExceededException)
{
try
{
response.getWriter().print(ErrorConstants.UPLOAD_SIZE_EXCEED + "," + (((MaxUploadSizeExceededException) ex).getMaxUploadSize()/(1024*1024)));
response.getWriter().flush();
response.flushBuffer();
return new ModelAndView();
}
catch(IOException e)
{
}
}
return null;
}
...
}
When i upload a very large file (more than ${file.upload.max_size}, about 700MB), CommonsMultipartResolver throws MaxUploadSizeExceededException immediately which I'm catching and handling it (writing in response.getWriter()) .But My problem: My browser upload-progress bar shows the file is still uploading!! Why?
UPDATE: I'm using:
Spring-*-3.0.5.RELEASE
commons-fileupload-1.1.1
and also tried:
Spring-*-3.1.2.RELEASE
commons-fileupload-1.3
and my AS:
Tomcat 6 (in development)
Jboss 7 (in production)
UPDATE 2: In the client side, i'm using GWT (I think it doesn't matter):
Uploading is started by clicking submitRequestButton:
#UiHandler("submitRequestButton")
public void submitRequestButtonClick(ClickEvent event)
{
try
{
// some validation
submitRequestButton.setEnabled(false);
uploadPanel.upload(model.getWorkshopHistoryModel()); // uploadPanel is from the CoupleUploadPanel type
}
catch(ValidationException exception)
{
// handle validation errors
}
catch(SerializationException e)
{
// handle serialization errors
}
}
I have a CoupleUploadPanel Widget for uploading (two files):
public class CoupleUploadPanel<T extends Serializable> extends FormPanel
{
public final static String CONTENT = "content";
private static final String FIRST_FILE = "firstFile";
private static final String SECOND_FILE = "secondFile";
private Hidden contentInput;
private FileUpload firstFileUploadInput;
private FileUpload secondFileUploadInput;
private SerializationStreamFactory factory;
public CoupleUploadPanel(UploadServletAsync<T> factory)
{
this(null,factory);
}
public CoupleUploadPanel(String url, UploadServletAsync<T> factory)
{
this.factory = (SerializationStreamFactory) factory;
if(url != null)
{
setAction(url);
}
init();
}
public CoupleUploadPanel(String target, String url, UploadServletAsync<T> factory)
{
super(target);
this.factory = (SerializationStreamFactory) factory;
if(url != null)
{
setAction(url);
}
init();
}
private void init()
{
setMethod("POST");
setEncoding(ENCODING_MULTIPART);
firstFileUploadInput = new FileUpload();
firstFileUploadInput.setName(CoupleUploadPanel.FIRST_FILE);
secondFileUploadInput = new FileUpload();
secondFileUploadInput.setName(CoupleUploadPanel.SECOND_FILE);
contentInput = new Hidden();
contentInput.setName(CONTENT);
VerticalPanel panel = new VerticalPanel();
panel.add(firstFileUploadInput);
panel.add(secondFileUploadInput);
panel.add(contentInput);
add(panel);
}
public void upload(T input) throws SerializationException
{
contentInput.setValue(serialize(input));
submit();
}
private String serialize(T input) throws SerializationException
{
SerializationStreamWriter writer = factory.createStreamWriter();
writer.writeObject(input);
return writer.toString();
}
}
We should pass a UploadServletAsync to CoupleUploadPanel constructor. UploadServletAsync and UploadServlet interfaces:
public interface UploadServletAsync<T extends Serializable>
{
void upload(T model, AsyncCallback<Void> callback);
}
public interface UploadServlet<T extends Serializable> extends RemoteService
{
void upload(T model);
}
So the uploadPanel will be instantiated in this way:
uploadPanel= new CoupleUploadPanel<WorkshopHistoryModel>((UploadFileServletAsync) GWT.create(UploadFileServlet.class));
uploadPanel.setAction(UploadFileServlet.URL);
And a SubmitCompeleteHandler added to uploadPanel (onSumbitComplete() will be called when submit completed and results passed to the client side):
uploadPanel.addSubmitCompleteHandler(new SubmitCompleteHandler()
{
#Override
public void onSubmitComplete(SubmitCompleteEvent event)
{
String s = event.getResults(); //contains whatever written by response.getWriter()
if(s == null)
{
// navigate to request list page
}
else
{
String[] response = s.split(",");
// based on response:
// show error messages if any error occurred in file upload
// else: navigate to upload result page
}
}
});
UploadFileServlet and UploadFileServletAsync interfaces:
public interface UploadFileServlet extends UploadServlet<WorkshopHistoryModel>
{
String URL = "**/uploadFileService.mvc";
}
public interface UploadFileServletAsync extends UploadServletAsync<WorkshopHistoryModel>
{
public static final UploadFileServletAsync INSTANCE = GWT.create(UploadFileServlet.class);
}
In the server side: the UploadFileServletImpl extends AbstractCoupleUploadController and implements the upload() method (upload process):
#RequestMapping(UploadFileServlet.URL)
public class UploadFileServletImpl extends AbstractCoupleUploadController<WorkshopHistoryModel>
{
...
#Override
protected UploadResultModel upload(WorkshopHistoryModel model, MultipartFile firstFile, MultipartFile secondFile)
throws ProcessRequestException
{
return workshopHistoryService.submitList(model.getWorkshop(),firstFile,secondFile);
}
...
}
Well, afaik Spring (a servlet and some filters) does not observe the uploading process, but only handle the result of the finished process. That's because the upload is processed by Tomcat itself (hint: there is an upload size limit option in the web.xml). So it can be possible to make an upload failure (which Spring would not be noticed) or to upload a file which is too large. And only when 2nd happend, the specific filter/interceptor could deny the process.
In my last setup, I had used Nginx as proxy in front of a Tomcat:
If your browser sends the actual file size (modern browsers do, at least IE7? or IE8? does not), than Nginx will send a 500 if the size exceeds the defined limit.
I'm not 100% sure: If the uploaded size exceeds the specified limit, Nginx will send a 500 too. That would cancel the underlaying connection to the Tomcat, too.
We use the following method:
public class MultipartResolver extends CommonsMultipartResolver {
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
try {
List fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
MultipartParsingResult parsingResult = parseFileItems(fileItems, encoding);
return new DefaultMultipartHttpServletRequest(
request, parsingResult.getMultipartFiles(), parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
} catch (FileUploadBase.SizeLimitExceededException ex) {
throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
}
catch (FileUploadException ex) {
throw new MultipartException("Could not parse multipart servlet request", ex);
}
}
public void cleanupMultipart(MultipartHttpServletRequest request) {
super.cleanupMultipart(request);
}
public void setFileSizeMax(long fileSizeMax) {
getFileUpload().setSizeMax(-1);
getFileUpload().setFileSizeMax(fileSizeMax);
}
}
As a first try I would call response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR) in MaxUploadSizeExceededExceptionHandler.
Then I would check one or two SO questions to see whether they would contain some helpful information I could try out.
If this doesn't help I would investigate the sources of GwtUpload and see how they implemented it (or just start using their implementation).
yourfile.getFile().getSize() > Long.parseLong(153600);
This code will approve to upload a file less than 150 kb.
If it exceeds 150 kb you can send any error msg.

GWT RequestBuilder - Cross Site Requests

I'm trying to make Cross Site Request using GWT Request builder, which i couldn't get it to work yet. As you can see, this is much of a Sample GWT Project and i have gone through https://developers.google.com/web-toolkit/doc/latest/tutorial/Xsite . But still i'm missing something.
I'm Posting the code here. What am i missing ..?
package com.gwt.reqbuilder.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
public class GWTRequestBuilder implements EntryPoint
{
private static final String JSON_URL = "http://localhost:8000/?q=ABC&callback=callback125";
public void onModuleLoad()
{
GWTPOSTHTTP();
}
public void GWTPOSTHTTP()
{
String postUrl="http://localhost:8000";
String requestData="q=ABC&callback=callback125";
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, postUrl);
try {
builder.sendRequest(requestData.toString(), new RequestCallback()
{
public void onError(Request request, Throwable e)
{
Window.alert(e.getMessage());
}
public void onResponseReceived(Request request, Response response)
{
if (200 == response.getStatusCode())
{
Window.alert(response.getText());
} else {
Window.alert("Received HTTP status code other than 200 : "+ response.getStatusText());
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
Window.alert(e.getMessage());
}
}
}
Actually we can make Cross Site Requests from GWT RequestBuilder if we can set in Servlet Response Header
Response.setHeader("Access-Control-Allow-Origin","http://myhttpserver");
It's working Cool , if anyone need the GWT Project and Python Servlet, please do let me know, i can upload the files.
GWT Client Code : https://github.com/manikandaraj/MLabs/tree/master/GWT/GWTClient
You've missed to finish reading the tutorial.
Direct quote from the tutorial :
The RequestBuilder code is replaced by a call to the getJson method. So you no longer need the following code in the refreshWatchList method:
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Couldn't retrieve JSON");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError("Couldn't retrieve JSON (" + response.getStatusText()
+ ")");
}
}
});
} catch (RequestException e) {
displayError("Couldn't retrieve JSON");
}
Which is broadly what you've got, and should be replaced by a JSNI function given in the tutorial a few lines below :
/**
* Make call to remote server.
*/
public native static void getJson(int requestId, String url,
StockWatcher handler) /*-{
var callback = "callback" + requestId;
// [1] Create a script element.
var script = document.createElement("script");
script.setAttribute("src", url+callback);
script.setAttribute("type", "text/javascript");
// [2] Define the callback function on the window object.
window[callback] = function(jsonObj) {
// [3]
handler.#com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
window[callback + "done"] = true;
}
...

Categories

Resources