blob: 1064c7c7d7918bf06e2a122cb52ea8fa5c64b974 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket.protocol.ws.api;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;
import jakarta.servlet.http.Cookie;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.http.WebResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A {@link Response} used to cache the written data to the web socket client
* when Wicket thread locals are available.
*
* When the thread locals are not available then you can write directly to the {@link IWebSocketConnection}
* taken from {@link org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry}.
* In this case the response wont be cached.
*
* @since 6.0
*/
public class WebSocketResponse extends WebResponse
{
private static final Logger LOG = LoggerFactory.getLogger(WebSocketResponse.class);
private final IWebSocketConnection connection;
private StringBuilder text;
private ByteArrayOutputStream binary;
private boolean isRedirect = false;
public WebSocketResponse(final IWebSocketConnection conn)
{
this.connection = conn;
}
@Override
public void write(CharSequence sequence)
{
if (text == null)
{
text = new StringBuilder();
}
text.append(sequence);
}
@Override
public void write(byte[] array)
{
write(array, 0, array.length);
}
@Override
public void write(byte[] array, int offset, int length)
{
if (binary == null)
{
binary = new ByteArrayOutputStream();
}
binary.write(array, offset, length);
}
@Override
public void close()
{
if (connection.isOpen())
{
try
{
if (text != null)
{
connection.sendMessage(text.toString());
text = null;
}
else if (binary != null)
{
byte[] bytes = binary.toByteArray();
connection.sendMessage(bytes, 0, bytes.length);
binary.close();
binary = null;
}
} catch (IOException iox)
{
LOG.error("An error occurred while writing response to WebSocket client.", iox);
}
}
super.close();
}
@Override
public void reset()
{
text = null;
if (binary != null)
{
try
{
binary.close();
} catch (IOException iox)
{
LOG.error("An error occurred while resetting the binary content", iox);
}
binary = null;
}
isRedirect = false;
super.reset();
}
@Override
public String encodeURL(CharSequence url)
{
return url.toString();
}
@Override
public final IWebSocketConnection getContainerResponse()
{
return connection;
}
@Override
public void addCookie(Cookie cookie)
{
throw new UnsupportedOperationException();
}
@Override
public void clearCookie(Cookie cookie)
{
throw new UnsupportedOperationException();
}
@Override
public boolean isHeaderSupported() {
return false;
}
@Override
public void setHeader(String name, String value)
{
throw new UnsupportedOperationException();
}
@Override
public void addHeader(String name, String value)
{
throw new UnsupportedOperationException();
}
@Override
public void setDateHeader(String name, Instant date)
{
throw new UnsupportedOperationException();
}
@Override
public void setContentLength(long length)
{
throw new UnsupportedOperationException();
}
@Override
public void setContentType(String mimeType)
{
throw new UnsupportedOperationException();
}
@Override
public void setStatus(int sc)
{
throw new UnsupportedOperationException();
}
@Override
public void sendError(int sc, String msg)
{
LOG.warn("An HTTP error response in WebSocket communication would not be processed by the browser! " +
"If you need to send the error code and message to the client then configure custom WebSocketResponse " +
"via WebSocketSettings#newWebSocketResponse() factory method and override #sendError() method to write " +
"them in an appropriate format for your application. " +
"The ignored error code is '{}' and the message: '{}'.", sc, msg);
}
@Override
public String encodeRedirectURL(CharSequence url)
{
return url.toString();
}
@Override
public void sendRedirect(String url)
{
isRedirect = true;
url = encodeRedirectURL(url);
String ajaxRedirect = "<ajax-response><redirect><![CDATA[" + url + "]]></redirect></ajax-response>";
write(ajaxRedirect);
}
@Override
public boolean isRedirect()
{
return isRedirect;
}
@Override
public void flush()
{
}
}