Skip to content

Commit

Permalink
Merge branch 'develop' into feature/aha/auto-determine-content-type
Browse files Browse the repository at this point in the history
  • Loading branch information
andyHa authored Jun 30, 2022
2 parents 5a710c3 + d4ad3aa commit e57c5d2
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 44 deletions.
37 changes: 33 additions & 4 deletions src/main/java/sirius/web/http/ChunkedOutputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.DefaultHttpContent;
import io.netty.handler.codec.http.DefaultLastHttpContent;
import io.netty.handler.codec.http.HttpHeaderNames;
Expand All @@ -23,18 +24,20 @@

import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;

/**
* Provides an adapter from {@link OutputStream} to an underlying channel using a buffer.
*/
class ChunkedOutputStream extends OutputStream {
public class ChunkedOutputStream extends OutputStream {
private final Response response;
private final String contentType;
private final HttpResponseStatus status;
private volatile boolean open;
private volatile boolean contentionControl;
private ByteBuf buffer;

ChunkedOutputStream(Response response, String contentType, HttpResponseStatus status) {
protected ChunkedOutputStream(Response response, String contentType, HttpResponseStatus status) {
this.response = response;
this.contentType = contentType;
this.status = status;
Expand Down Expand Up @@ -72,13 +75,39 @@ private void flushBuffer(boolean last) {
if (last) {
completeRequest();
} else {
Object message = new DefaultHttpContent(buffer);
response.ctx.writeAndFlush(message);
try {
Object message = new DefaultHttpContent(buffer);
ChannelFuture writeFuture = response.ctx.writeAndFlush(message);
if (contentionControl) {
writeFuture.await(60, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
Exceptions.handle()
.to(WebServer.LOG)
.error(e)
.withSystemErrorMessage("Got interrupted while waiting for data to be flushed: % (%s)")
.handle();

Thread.currentThread().interrupt();
}
}

buffer = null;
}

/**
* Enables automatic contention control.
* <p>
* This essentially blocks writes (once the internal buffer is full) until the data has been flushed out to the
* client.
*
* @return the stream itself for fluent method calls
*/
public ChunkedOutputStream enableContentionControl() {
this.contentionControl = true;
return this;
}

private void completeRequest() {
if (buffer != null) {
response.complete(response.ctx.writeAndFlush(new DefaultLastHttpContent(buffer)));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/sirius/web/http/Response.java
Original file line number Diff line number Diff line change
Expand Up @@ -1579,7 +1579,7 @@ public XMLStructuredOutput xml(HttpResponseStatus status) {
* @param contentType the content type to use. If <tt>null</tt>, we rely on a previously set header.
* @return an output stream which will be sent as response
*/
public OutputStream outputStream(HttpResponseStatus status, @Nullable String contentType) {
public ChunkedOutputStream outputStream(HttpResponseStatus status, @Nullable String contentType) {
if (wc.responseCommitted) {
throw Exceptions.createHandled()
.withSystemErrorMessage("Response for %s was already committed!", wc.getRequestedURI())
Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/default/assets/common/core.js.pasta
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ sirius.querySelector = function (query) {
}
}

/**@
* Clears the "display" property of the given element to make it visible.
* It is expected to be 'display: none' before.
*/
sirius.show = function(_element) {
_element.style.display = '';
}

/**@
* Tries to find the parent node of the given type.
*
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

19 changes: 0 additions & 19 deletions src/main/resources/default/assets/tycho/styles/misc.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,6 @@ a {

}

@media (min-width: 960px) {

.sticky-top-lg {
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1020;
}

.fixed-bottom-lg {
position: fixed;
bottom: 0;
right: 0;
left: 0;
z-index: 1030;
}

}

.nav-link .badge {
line-height: 1.5;
background-color: $sirius-gray;
Expand Down
37 changes: 31 additions & 6 deletions src/main/resources/default/assets/tycho/styles/page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,39 @@ body {
background-color: $backgroundGray;
}

#wrapper {
display: grid;
height: 100vh;
grid-template-rows: 80px 1fr 40px;
#wrapper-menu {
margin-bottom: 1rem;
}


#wrapper-body {
min-width: 0;
}

@media (min-width: 960px) {

#wrapper-body {
min-width: 0;
#wrapper {
display: grid;
height: 100vh;
grid-template-rows: 80px 1fr 40px;
}

#wrapper-menu {
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1020;
margin-bottom: 0;
}

#wrapper-footer {
position: fixed;
bottom: 0;
right: 0;
left: 0;
z-index: 1030;
}

}

nav.navbar {
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/default/taglib/t/page.html.pasta
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
</head>
<body>
<div id="wrapper">
<div id="wrapper-menu" class="sticky-top-lg">
<div id="wrapper-menu">
<i:render name="menu">
<i:invoke template="/templates/tycho/page-menu.html.pasta"/>
</i:render>
Expand Down Expand Up @@ -91,7 +91,7 @@
</i:else>
</i:if>
</div>
<div id="wrapper-footer" class="fixed-bottom-lg">
<div id="wrapper-footer">
<i:render name="footer">
<i:invoke template="/templates/tycho/page-footer.html.pasta"/>
</i:render>
Expand Down
30 changes: 26 additions & 4 deletions src/test/java/sirius/web/http/TestResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public void tunnel(String url) {
}

@Override
public OutputStream outputStream(HttpResponseStatus status, @Nullable String contentType) {
public ChunkedOutputStream outputStream(HttpResponseStatus status, @Nullable String contentType) {
type = ResponseType.STREAM;
this.status = status;
if (Strings.isFilled(contentType)) {
Expand All @@ -367,11 +367,33 @@ public OutputStream outputStream(HttpResponseStatus status, @Nullable String con
setContentDisposition(name, download);
}

return new ByteArrayOutputStream() {
return new ChunkedOutputStream(this, contentType, status) {

private final ByteArrayOutputStream delegate = new ByteArrayOutputStream();

@Override
public void write(int b) throws IOException {
delegate.write(b);
}

@Override
public void write(byte[] b) throws IOException {
delegate.write(b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
delegate.write(b, off, len);
}

@Override
public void flush() throws IOException {
delegate.flush();
}

@Override
public void close() throws IOException {
super.close();
content = toByteArray();
content = delegate.toByteArray();
completeResponse();
}
};
Expand Down

0 comments on commit e57c5d2

Please sign in to comment.