Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webclient redesign #7255

Merged
merged 21 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e72c3c2
WebClient, HTTP/1.1 webclient aligned
tomas-langer Jul 11, 2023
839ac3c
HTTP/2 webclient alignment (in progress)
tomas-langer Jul 19, 2023
811b736
Fixes after rebase (on reactive removal)
tomas-langer Jul 19, 2023
16029a1
Fix for #7223
tomas-langer Jul 19, 2023
3229698
Use UriInfo in WebClient, combined query and fragment with it
tomas-langer Jul 20, 2023
3a36581
Cookie support for webclient.
tomas-langer Jul 20, 2023
d6a2bf2
WebSocket now upgrades through API
tomas-langer Jul 20, 2023
6c8c125
HTTP/2 with services.
tomas-langer Jul 21, 2023
8c2e953
Change to service execution to support both versions of http
tomas-langer Jul 24, 2023
9f5ab4c
HTTP/2 and WebSocket test fixes
tomas-langer Jul 27, 2023
899d002
Typed client response fixes (so it does not need to be autocloseable)
tomas-langer Jul 27, 2023
004d7eb
Fix client entity reading, when chunked received over the network is …
tomas-langer Jul 27, 2023
bb26018
Copyright fixes
tomas-langer Jul 27, 2023
b187167
Fixed all tests and examples.
tomas-langer Jul 27, 2023
28ea46f
Checkstyle fixes
tomas-langer Jul 28, 2023
33933c7
Fixes after rebasing on latest `main`
tomas-langer Jul 28, 2023
9910fe5
Javadoc fixes.
tomas-langer Jul 28, 2023
1b5a364
Archetype fix.
tomas-langer Jul 28, 2023
4d6a689
Fixed error of not draining request when continue was already sent.
tomas-langer Jul 28, 2023
c13a123
Review fixes.
tomas-langer Jul 31, 2023
5c4e17d
Fix possible mutation of internal state of HeaderValue that is shared.
tomas-langer Jul 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package {{package}};

import io.helidon.common.http.Http;
import io.helidon.nima.webclient.WebClient;
import io.helidon.nima.webclient.http1.Http1Client;
import io.helidon.nima.webclient.api.WebClient;

/**
* Executable class that invokes HTTP/1 requests against the server.
Expand All @@ -17,19 +16,17 @@ public class GreetClientHttp {
* @param args ignored
*/
public static void main(String[] args) {
Http1Client client = WebClient.builder()
WebClient client = WebClient.builder()
.baseUri("http://localhost:8080/greet")
.build();

String response = client.method(Http.Method.GET)
.request()
.as(String.class);
.requestEntity(String.class);

System.out.println(response);

response = client.get("Nima")
.request()
.as(String.class);
.requestEntity(String.class);

System.out.println(response);
}
Expand Down
20 changes: 20 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1095,11 +1095,31 @@
<artifactId>helidon-nima-webserver-static-content</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient</groupId>
<artifactId>helidon-nima-webclient-api</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient</groupId>
<artifactId>helidon-nima-webclient-http1</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient</groupId>
<artifactId>helidon-nima-webclient</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient.dns.resolver</groupId>
<artifactId>helidon-nima-webclient-dns-resolver-first</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient.dns.resolver</groupId>
<artifactId>helidon-nima-webclient-dns-resolver-round-robin</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.webclient</groupId>
<artifactId>helidon-nima-webclient-security</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,10 @@ private void generatePrototypeWithBuilder(TypeElement builderInterface,
pw.println(javadocLine);
}
pw.println(" *");
pw.println(" * @see #builder()");
if (!propertyData.hasRequired() && blueprintDef.createEmptyPublic()) {
if (blueprintDef.builderPublic()) {
pw.println(" * @see #builder()");
}
if (!propertyData.hasRequired() && blueprintDef.createEmptyPublic() && blueprintDef.builderPublic()) {
pw.println(" * @see #create()");
}
pw.println(" */");
Expand Down Expand Up @@ -438,7 +440,7 @@ static X create(Config config)
pw.println();
}

if (blueprintDef.createEmptyPublic()) {
if (blueprintDef.createEmptyPublic() && blueprintDef.builderPublic()) {
/*
static X create()
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ static void generate(PrintWriter pw,
pw.println("> {");
pw.print(SOURCE_SPACING);
pw.print(SOURCE_SPACING);
pw.println("private Builder() {");
if (typeContext.blueprintData().builderPublic()) {
pw.println("private Builder() {");
} else {
// package private to allow instantiation
pw.println("Builder() {");
}
pw.print(SOURCE_SPACING);
pw.print(SOURCE_SPACING);
pw.println("}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,16 +300,14 @@ private static void gatherExtends(TypeInfo typeInfo, Set<TypeName> extendList,
// this is a prototype itself, ignore additional interfaces
gatherAll = false;
superPrototypes.add(info.typeName());
ignoredInterfaces.add(info.typeName());
ignoredInterfaces.add(TypeName.builder(info.typeName())
.className(info.typeName().className() + "Blueprint")
.build());
// also add all super interfaces of the prototype
info.interfaceTypeInfo()
.stream()
.map(TypeInfo::typeName)
.map(TypeName::genericTypeName)
.forEach(ignoredInterfaces::add);

// we need to ignore ANY interface implemented by "info" and its super interfaces
if (ignoredInterfaces.add(info.typeName().genericTypeName())) {
ignoredInterfaces.add(TypeName.builder(info.typeName())
.className(info.typeName().className() + "Blueprint")
.build());
ignoreAllInterfaces(ignoredInterfaces, info);
}
break;
}
}
Expand All @@ -319,6 +317,17 @@ private static void gatherExtends(TypeInfo typeInfo, Set<TypeName> extendList,
}
}

private static void ignoreAllInterfaces(Set<TypeName> ignoredInterfaces, TypeInfo info) {
// also add all super interfaces of the prototype
List<TypeInfo> superIfaces = info.interfaceTypeInfo();

for (TypeInfo superIface : superIfaces) {
if (ignoredInterfaces.add(superIface.typeName().genericTypeName())) {
ignoreAllInterfaces(ignoredInterfaces, superIface);
}
}
}

@SuppressWarnings("checkstyle:ParameterNumber") // we need all of them
private static void gatherBuilderProperties(ProcessingContext processingContext,
TypeInfo typeInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ TypeName actualType() {

@Override
Optional<String> generateFromConfig(PrototypeProperty.ConfiguredOption configured, FactoryMethods factoryMethods) {
if (STRING_TYPE.equals(actualType)) {
return Optional.of("config.get(\"" + configured.configKey() + "\").asMap().ifPresent(this::" + setterName() + ");");
}

return Optional.of("config.get(\"" + configured.configKey() + "\").asNodeList().ifPresent(nodes -> nodes.forEach"
+ "(node -> "
+ name() + ".put(node.get(\"name\").asString().orElse(node.name()), node"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -210,7 +210,7 @@ static BufferData create(String stringValue) {
* Read bytes from the input stream.
* Reads at least 1 byte.
* @param in input stream
* @return number of bytes read
* @return number of bytes read, -1 if the input stream is finished
*/
int readFrom(InputStream in);

Expand Down Expand Up @@ -574,7 +574,7 @@ default BufferData copy() {
/**
* Number of bytes available for reading.
*
* @return available byte
* @return available bytes
*/
int available();

Expand Down Expand Up @@ -642,4 +642,16 @@ default void writeAscii(String text) {
* @return byte at the index
*/
int get(int index);

/**
* Read the content of this data as bytes.
* This method always creates a new byte array.
*
* @return byte array with {@link #available()} bytes, may be empty
*/
default byte[] readBytes() {
byte[] bytes = new byte[available()];
read(bytes);
return bytes;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -163,11 +163,17 @@ public T remove(HeaderName name, Consumer<HeaderValue> removedConsumer) {
@Override
public T set(HeaderValue header) {
HeaderName name = header.headerName();

HeaderValue usedHeader = header;
if (header instanceof HeaderValueWriteable) {
// we must create a new instance, as we risk modifying state of the provided header
usedHeader = new HeaderValueCopy(header);
}
int index = name.index();
if (index == -1) {
customHeaders.put(name, header);
customHeaders.put(name, usedHeader);
} else {
knownHeaders[index] = header;
knownHeaders[index] = usedHeader;
knownHeaderIndices.add(index);
}
return (T) this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import io.helidon.common.config.Config;
import io.helidon.common.configurable.AllowList;
Expand Down Expand Up @@ -289,7 +288,7 @@ public UriInfo uriInfo(String remoteAddress,
String requestPath,
ServerRequestHeaders headers,
UriQuery query,
boolean isSecure) {
boolean isSecure) {
String scheme = null;
String authority = null;
String host = null;
Expand Down Expand Up @@ -340,34 +339,28 @@ public UriInfo uriInfo(String remoteAddress,
}
}

UriInfo.Builder uriInfo = UriInfo.builder();

// now we must fill values that were not discovered (to have a valid URI information)
if (host == null && authority == null) {
authority = headers.first(Http.Header.HOST).orElse(null);
}

if (path == null) {
path = requestPath;
uriInfo.path(path == null ? requestPath : path);
uriInfo.host(localAddress); // this is the fallback
if (authority != null) {
uriInfo.authority(authority); // this is the second possibility
}

if (host == null && authority != null) {
Authority a;
if (scheme == null) {
a = Authority.create(authority);
} else {
a = Authority.create(scheme, authority);
}
if (a.host() != null) {
host = a.host();
}
if (port == -1) {
port = a.port();
}
if (host != null) {
uriInfo.host(host); // and this one has priority
}
if (port != -1) {
uriInfo.port(port);
}

/*
Discover final values to be used
*/

/*
Discover final values to be used
*/
if (scheme == null) {
if (port == 80) {
scheme = "http";
Expand All @@ -377,23 +370,10 @@ public UriInfo uriInfo(String remoteAddress,
scheme = isSecure ? "https" : "http";
}
}
uriInfo.scheme(scheme);
uriInfo.query(query);

if (host == null) {
host = localAddress;
}

// we may still have -1, if port was not explicitly defined by a header - use default port of protocol
if (port == -1) {
if ("https".equals(scheme)) {
port = 443;
} else {
port = 80;
}
}
if (query == null || query.isEmpty()) {
query = null;
}
return new UriInfo(scheme, host, port, path, Optional.ofNullable(query));
return uriInfo.build();
}

private static String hostPart(String address) {
Expand Down Expand Up @@ -467,29 +447,6 @@ private XForwardedDiscovery discoverUsingXForwarded(ServerRequestHeaders headers
return discovered ? new XForwardedDiscovery(scheme, host, port, path) : null;
}

private record Authority(String host, int port) {
static Authority create(String hostHeader) {
int colon = hostHeader.indexOf(':');
if (colon == -1) {
// we do not know the protocol, and there is no port defined
return new Authority(hostHeader, -1);
}
String hostString = hostHeader.substring(0, colon);
String portString = hostHeader.substring(colon + 1);
return new Authority(hostString, Integer.parseInt(portString));
}
static Authority create(String scheme, String hostHeader) {
int colon = hostHeader.indexOf(':');
if (colon == -1) {
// define port by protocol
return new Authority(hostHeader, "https".equals(scheme) ? 443 : 80);
}
String hostString = hostHeader.substring(0, colon);
String portString = hostHeader.substring(colon + 1);
return new Authority(hostString, Integer.parseInt(portString));
}
}

private record ForwardedDiscovery(String authority, String scheme) {}
private record XForwardedDiscovery(String scheme, String host, int port, String path) {}

Expand Down
Loading