Skip to content

Commit bf097e6

Browse files
committed
[UNDERTOW-1497] add request body ready bytes attribute
1 parent b44a1c3 commit bf097e6

File tree

6 files changed

+112
-0
lines changed

6 files changed

+112
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
* Copyright 2024 Red Hat, Inc., and individual contributors
4+
* as indicated by the @author tags.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package io.undertow.attribute;
20+
21+
import io.undertow.server.HttpServerExchange;
22+
23+
/**
24+
* The bytes sent
25+
*
26+
* @author baranowb
27+
*/
28+
public class BytesReadAttribute implements ExchangeAttribute {
29+
30+
public static final String BYTES_READ_SHORT_UPPER = "%X";
31+
public static final String BYTES_READ_SHORT_LOWER = "%x";
32+
public static final String BYTES_READ = "%{BYTES_READ}";
33+
34+
private final boolean dashIfZero;
35+
36+
public BytesReadAttribute(boolean dashIfZero) {
37+
this.dashIfZero = dashIfZero;
38+
}
39+
40+
41+
@Override
42+
public String readAttribute(final HttpServerExchange exchange) {
43+
if (dashIfZero ) {
44+
long bytesSent = exchange.getRequestBytesRead();
45+
return bytesSent == 0 ? "-" : Long.toString(bytesSent);
46+
} else {
47+
return Long.toString(exchange.getRequestBytesRead());
48+
}
49+
}
50+
51+
@Override
52+
public void writeAttribute(final HttpServerExchange exchange, final String newValue) throws ReadOnlyAttributeException {
53+
throw new ReadOnlyAttributeException("Bytes read", newValue);
54+
}
55+
56+
@Override
57+
public String toString() {
58+
return BYTES_READ;
59+
}
60+
61+
public static final class Builder implements ExchangeAttributeBuilder {
62+
63+
@Override
64+
public String name() {
65+
return "Bytes Read";
66+
}
67+
68+
@Override
69+
public ExchangeAttribute build(final String token) {
70+
if(token.equals(BYTES_READ_SHORT_LOWER)) {
71+
return new BytesReadAttribute(true);
72+
}
73+
if (token.equals(BYTES_READ) || token.equals(BYTES_READ_SHORT_UPPER)) {
74+
return new BytesReadAttribute(false);
75+
}
76+
return null;
77+
}
78+
79+
@Override
80+
public int priority() {
81+
return 0;
82+
}
83+
}
84+
}

core/src/main/java/io/undertow/io/UndertowInputStream.java

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package io.undertow.io;
2020

2121
import io.undertow.UndertowMessages;
22+
import io.undertow.server.Connectors;
2223
import io.undertow.server.HttpServerExchange;
2324
import io.undertow.connector.ByteBufferPool;
2425
import io.undertow.connector.PooledByteBuffer;
@@ -49,6 +50,7 @@ public class UndertowInputStream extends InputStream {
4950
private final StreamSourceChannel channel;
5051
private final ByteBufferPool bufferPool;
5152
private final int readTimeout;
53+
private final HttpServerExchange exchange;
5254

5355
/**
5456
* If this stream is ready for a read
@@ -60,6 +62,7 @@ public class UndertowInputStream extends InputStream {
6062
private PooledByteBuffer pooled;
6163

6264
public UndertowInputStream(final HttpServerExchange exchange) {
65+
this.exchange = exchange;
6366
if (exchange.isRequestChannelAvailable()) {
6467
this.channel = exchange.getRequestChannel();
6568
} else {
@@ -123,6 +126,7 @@ public int read(final byte[] b, final int off, final int len) throws IOException
123126
pooled.close();
124127
pooled = null;
125128
}
129+
Connectors.updateRequestBytesRead(exchange, copied);
126130
return copied;
127131
}
128132

core/src/main/java/io/undertow/server/Connectors.java

+4
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,10 @@ public static void updateResponseBytesSent(HttpServerExchange exchange, long byt
610610
exchange.updateBytesSent(bytes);
611611
}
612612

613+
public static void updateRequestBytesRead(HttpServerExchange exchange, long bytes) {
614+
exchange.updateBytesRead(bytes);
615+
}
616+
613617
public static ConduitStreamSinkChannel getConduitSinkChannel(HttpServerExchange exchange) {
614618
return exchange.getConnection().getSinkChannel();
615619
}

core/src/main/java/io/undertow/server/HttpServerExchange.java

+17
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ public final class HttpServerExchange extends AbstractAttachable {
262262
*/
263263
private long responseBytesSent = 0;
264264

265+
/**
266+
* The number of bytes that have been read from remote client. This does not include headers,
267+
* only the entity body, and does not take any transfer or content encoding into account.
268+
*/
269+
private long requestBytesRead = 0;
265270

266271
private static final int MASK_RESPONSE_CODE = intBitMask(0, 9);
267272

@@ -761,6 +766,14 @@ public long getResponseBytesSent() {
761766
}
762767
}
763768

769+
/**
770+
*
771+
* @return numbers of bytes read from request body
772+
*/
773+
public long getRequestBytesRead() {
774+
return this.requestBytesRead;
775+
}
776+
764777
/**
765778
* Updates the number of response bytes sent. Used when compression is in use
766779
* @param bytes The number of bytes to increase the response size by. May be negative
@@ -771,6 +784,10 @@ void updateBytesSent(long bytes) {
771784
}
772785
}
773786

787+
void updateBytesRead(long bytes) {
788+
requestBytesRead += bytes;
789+
}
790+
774791
public HttpServerExchange setPersistent(final boolean persistent) {
775792
if (persistent) {
776793
setFlags(FLAG_PERSISTENT);

core/src/main/resources/META-INF/services/io.undertow.attribute.ExchangeAttributeBuilder

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ io.undertow.attribute.RequestMethodAttribute$Builder
88
io.undertow.attribute.QueryStringAttribute$Builder
99
io.undertow.attribute.RequestLineAttribute$Builder
1010
io.undertow.attribute.BytesSentAttribute$Builder
11+
io.undertow.attribute.BytesReadAttribute$Builder
1112
io.undertow.attribute.DateTimeAttribute$Builder
1213
io.undertow.attribute.RemoteUserAttribute$Builder
1314
io.undertow.attribute.RequestURLAttribute$Builder

servlet/src/main/java/io/undertow/servlet/spec/ServletInputStreamImpl.java

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.xnio.channels.StreamSourceChannel;
3636
import io.undertow.connector.ByteBufferPool;
3737
import io.undertow.connector.PooledByteBuffer;
38+
import io.undertow.server.Connectors;
3839
import io.undertow.servlet.UndertowServletMessages;
3940

4041
/**
@@ -191,6 +192,7 @@ public int read(final byte[] b, final int off, final int len) throws IOException
191192
readIntoBufferNonBlocking();
192193
}
193194
}
195+
Connectors.updateRequestBytesRead(request.getExchange(), copied);
194196
return copied;
195197
}
196198

0 commit comments

Comments
 (0)