# HG changeset patch # User coleenp # Date 1566481999 14400 # Node ID 0094711309c3c922247ed7fce56246db9b1bf57a # Parent 4863a802a7c1412482df7e59587edea252d8ee2a# Parent de0ccdc4db1357ee53ad5b134daf926f7cb603b8 Merge diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp Thu Aug 22 09:53:19 2019 -0400 @@ -2265,7 +2265,7 @@ cmpdi(CCR0, Rcounters, 0); bne(CCR0, has_counters); call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::build_method_counters), method, false); + InterpreterRuntime::build_method_counters), method); ld(Rcounters, in_bytes(Method::method_counters_offset()), method); cmpdi(CCR0, Rcounters, 0); beq(CCR0, skip); // No MethodCounters, OutOfMemory. diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/cpu/s390/interp_masm_s390.cpp --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp Thu Aug 22 09:53:19 2019 -0400 @@ -1914,7 +1914,7 @@ load_and_test_long(Rcounters, Address(Rmethod, Method::method_counters_offset())); z_brnz(has_counters); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), Rmethod, false); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters), Rmethod); z_ltgr(Rcounters, Z_RET); // Runtime call returns MethodCounters object. z_brz(skip); // No MethodCounters, out of memory. diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/cpu/zero/globalDefinitions_zero.hpp --- a/src/hotspot/cpu/zero/globalDefinitions_zero.hpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/cpu/zero/globalDefinitions_zero.hpp Thu Aug 22 09:53:19 2019 -0400 @@ -30,6 +30,8 @@ #define SUPPORTS_NATIVE_CX8 #endif +#define THREAD_LOCAL_POLL + #include // Indicates whether the C calling conventions require that diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/cpu/zero/globals_zero.hpp --- a/src/hotspot/cpu/zero/globals_zero.hpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/cpu/zero/globals_zero.hpp Thu Aug 22 09:53:19 2019 -0400 @@ -76,7 +76,7 @@ // No performance work done here yet. define_pd_global(bool, CompactStrings, false); -define_pd_global(bool, ThreadLocalHandshakes, false); +define_pd_global(bool, ThreadLocalHandshakes, true); #define ARCH_FLAGS(develop, \ product, \ diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/share/asm/codeBuffer.cpp --- a/src/hotspot/share/asm/codeBuffer.cpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/share/asm/codeBuffer.cpp Thu Aug 22 09:53:19 2019 -0400 @@ -1050,10 +1050,11 @@ friend class CodeStrings; const char * _string; CodeString* _next; + CodeString* _prev; intptr_t _offset; ~CodeString() { - assert(_next == NULL, "wrong interface for freeing list"); + assert(_next == NULL && _prev == NULL, "wrong interface for freeing list"); os::free((void*)_string); } @@ -1061,7 +1062,7 @@ public: CodeString(const char * string, intptr_t offset = -1) - : _next(NULL), _offset(offset) { + : _next(NULL), _prev(NULL), _offset(offset) { _string = os::strdup(string, mtCode); } @@ -1069,7 +1070,12 @@ intptr_t offset() const { assert(_offset >= 0, "offset for non comment?"); return _offset; } CodeString* next() const { return _next; } - void set_next(CodeString* next) { _next = next; } + void set_next(CodeString* next) { + _next = next; + if (next != NULL) { + next->_prev = this; + } + } CodeString* first_comment() { if (is_comment()) { @@ -1097,12 +1103,9 @@ // Convenience for add_comment. CodeString* CodeStrings::find_last(intptr_t offset) const { - CodeString* a = find(offset); - if (a != NULL) { - CodeString* c = NULL; - while (((c = a->next_comment()) != NULL) && (c->offset() == offset)) { - a = c; - } + CodeString* a = _strings_last; + while (a != NULL && !a->is_comment() && a->offset() > offset) { + a = a->_prev; } return a; } @@ -1121,12 +1124,16 @@ c->set_next(_strings); _strings = c; } + if (c->next() == NULL) { + _strings_last = c; + } } void CodeStrings::assign(CodeStrings& other) { other.check_valid(); assert(is_null(), "Cannot assign onto non-empty CodeStrings"); _strings = other._strings; + _strings_last = other._strings_last; #ifdef ASSERT _defunct = false; #endif @@ -1142,8 +1149,11 @@ assert(is_null(), "Cannot copy onto non-empty CodeStrings"); CodeString* n = other._strings; CodeString** ps = &_strings; + CodeString* prev = NULL; while (n != NULL) { *ps = new CodeString(n->string(),n->offset()); + (*ps)->_prev = prev; + prev = *ps; ps = &((*ps)->_next); n = n->next(); } @@ -1180,6 +1190,10 @@ // unlink the node from the list saving a pointer to the next CodeString* p = n->next(); n->set_next(NULL); + if (p != NULL) { + assert(p->_prev == n, "missing prev link"); + p->_prev = NULL; + } delete n; n = p; } @@ -1190,6 +1204,9 @@ check_valid(); CodeString* s = new CodeString(string); s->set_next(_strings); + if (_strings == NULL) { + _strings_last = s; + } _strings = s; assert(s->string() != NULL, "should have a string"); return s->string(); diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/share/asm/codeBuffer.hpp --- a/src/hotspot/share/asm/codeBuffer.hpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/share/asm/codeBuffer.hpp Thu Aug 22 09:53:19 2019 -0400 @@ -249,6 +249,7 @@ private: #ifndef PRODUCT CodeString* _strings; + CodeString* _strings_last; #ifdef ASSERT // Becomes true after copy-out, forbids further use. bool _defunct; // Zero bit pattern is "valid", see memset call in decode_env::decode_env @@ -262,6 +263,7 @@ void set_null_and_invalidate() { #ifndef PRODUCT _strings = NULL; + _strings_last = NULL; #ifdef ASSERT _defunct = true; #endif @@ -272,6 +274,7 @@ CodeStrings() { #ifndef PRODUCT _strings = NULL; + _strings_last = NULL; #ifdef ASSERT _defunct = false; #endif diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/share/ci/ciMethodData.cpp --- a/src/hotspot/share/ci/ciMethodData.cpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/share/ci/ciMethodData.cpp Thu Aug 22 09:53:19 2019 -0400 @@ -258,12 +258,14 @@ void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) { for (uint row = 0; row < row_limit(); row++) { Klass* k = data->as_ReceiverTypeData()->receiver(row); - if (k != NULL && k->is_loader_alive()) { - ciKlass* klass = CURRENT_ENV->get_klass(k); - set_receiver(row, klass); - } else { - // With concurrent class unloading, the MDO could have stale metadata; override it - clear_row(row); + if (k != NULL) { + if (k->is_loader_alive()) { + ciKlass* klass = CURRENT_ENV->get_klass(k); + set_receiver(row, klass); + } else { + // With concurrent class unloading, the MDO could have stale metadata; override it + clear_row(row); + } } } } diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Thu Aug 22 09:53:19 2019 -0400 @@ -71,10 +71,10 @@ template ShenandoahWeakRoots::ShenandoahWeakRoots() : - _jni_roots(JNIHandles::weak_global_handles(), ShenandoahPhaseTimings::JNIWeakRoots), - _string_table_roots(StringTable::weak_storage(), ShenandoahPhaseTimings::StringTableRoots), - _resolved_method_table_roots(ResolvedMethodTable::weak_storage(), ShenandoahPhaseTimings::ResolvedMethodTableRoots), - _vm_roots(SystemDictionary::vm_weak_oop_storage(), ShenandoahPhaseTimings::VMWeakRoots) { + _jni_roots(OopStorageSet::jni_weak(), ShenandoahPhaseTimings::JNIWeakRoots), + _string_table_roots(OopStorageSet::string_table_weak(), ShenandoahPhaseTimings::StringTableRoots), + _resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), ShenandoahPhaseTimings::ResolvedMethodTableRoots), + _vm_roots(OopStorageSet::vm_weak(), ShenandoahPhaseTimings::VMWeakRoots) { } template @@ -87,10 +87,10 @@ } inline ShenandoahWeakRoots::ShenandoahWeakRoots() : - _jni_roots(JNIHandles::weak_global_handles(), ShenandoahPhaseTimings::JNIWeakRoots), - _string_table_roots(StringTable::weak_storage(), ShenandoahPhaseTimings::StringTableRoots), - _resolved_method_table_roots(ResolvedMethodTable::weak_storage(), ShenandoahPhaseTimings::ResolvedMethodTableRoots), - _vm_roots(SystemDictionary::vm_weak_oop_storage(), ShenandoahPhaseTimings::VMWeakRoots) { + _jni_roots(OopStorageSet::jni_weak(), ShenandoahPhaseTimings::JNIWeakRoots), + _string_table_roots(OopStorageSet::string_table_weak(), ShenandoahPhaseTimings::StringTableRoots), + _resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), ShenandoahPhaseTimings::ResolvedMethodTableRoots), + _vm_roots(OopStorageSet::vm_weak(), ShenandoahPhaseTimings::VMWeakRoots) { } template @@ -109,8 +109,8 @@ template ShenandoahVMRoots::ShenandoahVMRoots() : - _jni_handle_roots(JNIHandles::global_handles(), ShenandoahPhaseTimings::JNIRoots), - _vm_global_roots(SystemDictionary::vm_global_oop_storage(), ShenandoahPhaseTimings::VMGlobalRoots) { + _jni_handle_roots(OopStorageSet::jni_global(), ShenandoahPhaseTimings::JNIRoots), + _vm_global_roots(OopStorageSet::vm_global(), ShenandoahPhaseTimings::VMGlobalRoots) { } template diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp Thu Aug 22 09:53:19 2019 -0400 @@ -184,47 +184,3 @@ ShenandoahThreadLocalData::set_worker_id(thr, ShenandoahThreadLocalData::INVALID_WORKER_ID); #endif } - -struct PhaseMap { - WeakProcessorPhases::Phase _weak_processor_phase; - ShenandoahPhaseTimings::GCParPhases _shenandoah_phase; -}; - -static const struct PhaseMap phase_mapping[] = { -#if INCLUDE_JVMTI - {WeakProcessorPhases::jvmti, ShenandoahPhaseTimings::JVMTIWeakRoots}, -#endif -#if INCLUDE_JFR - {WeakProcessorPhases::jfr, ShenandoahPhaseTimings::JFRWeakRoots}, -#endif - {WeakProcessorPhases::jni, ShenandoahPhaseTimings::JNIWeakRoots}, - {WeakProcessorPhases::stringtable, ShenandoahPhaseTimings::StringTableRoots}, - {WeakProcessorPhases::resolved_method_table, ShenandoahPhaseTimings::ResolvedMethodTableRoots}, - {WeakProcessorPhases::vm, ShenandoahPhaseTimings::VMWeakRoots} -}; - -STATIC_ASSERT(sizeof(phase_mapping) / sizeof(PhaseMap) == WeakProcessorPhases::phase_count); - -void ShenandoahTimingConverter::weak_processing_timing_to_shenandoah_timing(WeakProcessorPhaseTimes* weak_processing_timings, - ShenandoahWorkerTimings* sh_worker_times) { - assert(weak_processing_timings->max_threads() == weak_processing_timings->max_threads(), "Must match"); - for (uint index = 0; index < WeakProcessorPhases::phase_count; index ++) { - weak_processing_phase_to_shenandoah_phase(phase_mapping[index]._weak_processor_phase, - weak_processing_timings, - phase_mapping[index]._shenandoah_phase, - sh_worker_times); - } -} - -void ShenandoahTimingConverter::weak_processing_phase_to_shenandoah_phase(WeakProcessorPhases::Phase wpp, - WeakProcessorPhaseTimes* weak_processing_timings, - ShenandoahPhaseTimings::GCParPhases spp, - ShenandoahWorkerTimings* sh_worker_times) { - if (WeakProcessorPhases::is_serial(wpp)) { - sh_worker_times->record_time_secs(spp, 0, weak_processing_timings->phase_time_sec(wpp)); - } else { - for (uint index = 0; index < weak_processing_timings->max_threads(); index ++) { - sh_worker_times->record_time_secs(spp, index, weak_processing_timings->worker_time_sec(index, wpp)); - } - } -} diff -r 4863a802a7c1 -r 0094711309c3 src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp Thu Aug 22 09:51:36 2019 -0400 +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp Thu Aug 22 09:53:19 2019 -0400 @@ -175,15 +175,4 @@ } }; -class ShenandoahTimingConverter : public AllStatic { -public: - static void weak_processing_timing_to_shenandoah_timing(WeakProcessorPhaseTimes* weak_processing_timings, - ShenandoahWorkerTimings* sh_worker_times); -private: - static void weak_processing_phase_to_shenandoah_phase(WeakProcessorPhases::Phase wpp, - WeakProcessorPhaseTimes* weak_processing_timings, - ShenandoahPhaseTimings::GCParPhases spp, - ShenandoahWorkerTimings* sh_worker_times); -}; - #endif // SHARE_GC_SHENANDOAH_SHENANDOAHUTILS_HPP diff -r 4863a802a7c1 -r 0094711309c3 src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java --- a/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java Thu Aug 22 09:51:36 2019 -0400 +++ b/src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java Thu Aug 22 09:53:19 2019 -0400 @@ -29,11 +29,17 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.PasswordAuthentication; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; import java.io.IOException; import java.io.OutputStream; +import java.util.Arrays; import java.util.Base64; import java.util.Objects; import sun.net.www.HeaderParser; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.ISO_8859_1; /** * BasicAuthentication: Encapsulate an http server authentication using @@ -49,37 +55,18 @@ /** The authentication string for this host, port, and realm. This is a simple BASE64 encoding of "login:password". */ - String auth; + final String auth; /** * Create a BasicAuthentication */ public BasicAuthentication(boolean isProxy, String host, int port, String realm, PasswordAuthentication pw, - String authenticatorKey) { + boolean isUTF8, String authenticatorKey) { super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION, AuthScheme.BASIC, host, port, realm, Objects.requireNonNull(authenticatorKey)); - String plain = pw.getUserName() + ":"; - byte[] nameBytes = null; - try { - nameBytes = plain.getBytes("ISO-8859-1"); - } catch (java.io.UnsupportedEncodingException uee) { - assert false; - } - - // get password bytes - char[] passwd = pw.getPassword(); - byte[] passwdBytes = new byte[passwd.length]; - for (int i=0; i retry_limit) { throw new IOException("too many authentication attempts. Limit: " + @@ -328,14 +336,14 @@ if (pw == null) { throw new IOException("No credentials provided"); } - au = au.retryWithCredentials(pw); + au = au.retryWithCredentials(pw, isUTF8); if (proxy) { exchange.proxyauth = au; } else { exchange.serverauth = au; } req = HttpRequestImpl.newInstanceForAuthentication(req); - addBasicCredentials(req, proxy, au.credentials); + addBasicCredentials(req, proxy, au.credentials, isUTF8); au.retries++; return req; } @@ -387,9 +395,9 @@ synchronized void store(String authscheme, URI domain, boolean proxy, - PasswordAuthentication value) { + PasswordAuthentication value, boolean isUTF8) { remove(authscheme, domain, proxy); - entries.add(new CacheEntry(authscheme, domain, proxy, value)); + entries.add(new CacheEntry(authscheme, domain, proxy, value, isUTF8)); } } @@ -417,15 +425,17 @@ final String scheme; final boolean proxy; final PasswordAuthentication value; + final boolean isUTF8; CacheEntry(String authscheme, URI uri, boolean proxy, - PasswordAuthentication value) { + PasswordAuthentication value, boolean isUTF8) { this.scheme = authscheme; this.root = normalize(uri, true).toString(); // remove extraneous components this.proxy = proxy; this.value = value; + this.isUTF8 = isUTF8; } public PasswordAuthentication value() { diff -r 4863a802a7c1 -r 0094711309c3 src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java Thu Aug 22 09:51:36 2019 -0400 +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/BasicAuthenticator.java Thu Aug 22 09:53:19 2019 -0400 @@ -25,7 +25,11 @@ package com.sun.net.httpserver; +import java.nio.charset.Charset; import java.util.Base64; +import java.util.Objects; + +import static java.nio.charset.StandardCharsets.UTF_8; /** * BasicAuthenticator provides an implementation of HTTP Basic @@ -35,15 +39,44 @@ */ public abstract class BasicAuthenticator extends Authenticator { - protected String realm; + protected final String realm; + protected final Charset charset; + private final boolean isUTF8; + + /** + * Creates a BasicAuthenticator for the given HTTP realm. + * The Basic authentication credentials (username and password) are decoded + * using the platform's {@link Charset#defaultCharset() default character set}. + * + * @param realm The HTTP Basic authentication realm + * @throws NullPointerException if realm is {@code null} + * @throws IllegalArgumentException if realm is an empty string + */ + public BasicAuthenticator (String realm) { + this(realm, Charset.defaultCharset()); + } /** - * Creates a BasicAuthenticator for the given HTTP realm + * Creates a BasicAuthenticator for the given HTTP realm and using the + * given {@link Charset} to decode the Basic authentication credentials + * (username and password). + * + * @apiNote {@code UTF-8} is the recommended charset because its usage is + * communicated to the client, and therefore more likely to be used also + * by the client. + * * @param realm The HTTP Basic authentication realm - * @throws NullPointerException if the realm is an empty string + * @param charset The Charset to decode incoming credentials from the client + * @throws NullPointerException if realm or charset are {@code null} + * @throws IllegalArgumentException if realm is an empty string */ - public BasicAuthenticator (String realm) { + public BasicAuthenticator (String realm, Charset charset) { + Objects.requireNonNull(charset); + if (realm.isEmpty()) // implicit NPE check + throw new IllegalArgumentException("realm must not be empty"); this.realm = realm; + this.charset = charset; + this.isUTF8 = charset.equals(UTF_8); } /** @@ -63,7 +96,9 @@ String auth = rmap.getFirst ("Authorization"); if (auth == null) { Headers map = t.getResponseHeaders(); - map.set ("WWW-Authenticate", "Basic realm=" + "\""+realm+"\""); + var authString = "Basic realm=" + "\"" + realm + "\"" + + (isUTF8 ? " charset=\"UTF-8\"" : ""); + map.set ("WWW-Authenticate", authString); return new Authenticator.Retry (401); } int sp = auth.indexOf (' '); @@ -71,7 +106,7 @@ return new Authenticator.Failure (401); } byte[] b = Base64.getDecoder().decode(auth.substring(sp+1)); - String userpass = new String (b); + String userpass = new String (b, charset); int colon = userpass.indexOf (':'); String uname = userpass.substring (0, colon); String pass = userpass.substring (colon+1); diff -r 4863a802a7c1 -r 0094711309c3 test/hotspot/jtreg/ProblemList.txt --- a/test/hotspot/jtreg/ProblemList.txt Thu Aug 22 09:51:36 2019 -0400 +++ b/test/hotspot/jtreg/ProblemList.txt Thu Aug 22 09:53:19 2019 -0400 @@ -49,9 +49,8 @@ compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java 8163894 generic-all compiler/tiered/LevelTransitionTest.java 8067651 generic-all -compiler/types/correctness/CorrectnessTest.java 8225620 solaris-sparcv9 -compiler/types/correctness/OffTest.java 8225620 solaris-sparcv9 -compiler/unsafe/UnsafeGetConstantField.java 8229446 solaris-sparcv9 +compiler/types/correctness/CorrectnessTest.java 8230019,8225620 generic-all,solaris-sparcv9 +compiler/types/correctness/OffTest.java 8230019,8225620 generic-all,solaris-sparcv9 compiler/c2/Test6852078.java 8194310 generic-all compiler/c2/Test8004741.java 8214904 generic-all diff -r 4863a802a7c1 -r 0094711309c3 test/jdk/com/sun/net/httpserver/bugs/8199849/BasicAuthenticatorCharset.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/com/sun/net/httpserver/bugs/8199849/BasicAuthenticatorCharset.java Thu Aug 22 09:53:19 2019 -0400 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8199849 + * @library /test/lib + * @run main/othervm/timeout=6000 BasicAuthenticatorCharset + * @summary Check for correct use of character sets with BasicAuthenticator() authentication + */ + +import com.sun.net.httpserver.*; +import jdk.test.lib.net.URIBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.net.*; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.nio.charset.Charset; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.ISO_8859_1; + +/** + * Test authentication + */ + +public class BasicAuthenticatorCharset { + + public static volatile int failCount = 0; + + static final String TEST_USER = "test"; + static final String UNICODE_PW = "Selam D\u00fcnya. Ho\u015f\u00e7akal D\u00fcnya"; + + static Handler testHandler; + static HttpServer testHttpServer; + static java.net.Authenticator clientAuth; + static HttpClient client; + + static class Handler implements HttpHandler { + public void handle(HttpExchange t) throws IOException { + InputStream is = t.getRequestBody(); + while (is.read() != -1) ; + is.close(); + t.sendResponseHeaders(200, -1); + t.close(); + } + } + + static class ClientAuthenticator extends java.net.Authenticator { + public PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(TEST_USER, UNICODE_PW.toCharArray()); + } + } + + static void setAuthenticationPW(String path, String realm, String testPW, Charset charset) { + HttpContext ctx = testHttpServer.createContext(path, testHandler); + BasicAuthenticator auth; + if (charset != null) { + auth = new BasicAuthenticator(realm, charset) { + public boolean checkCredentials(String username, String pw) { + return username.equals(TEST_USER) && pw.equals(testPW); + } + }; + } else { + auth = new BasicAuthenticator(realm) { + public boolean checkCredentials(String username, String pw) { + return username.equals(TEST_USER) && pw.equals(testPW); + } + }; + } + ctx.setAuthenticator(auth); + } + + static void connectAndAuth(String path, int expectedStatus) throws Exception { + // path is prepended with /old or /new for old and new http client + URL oldurl = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(testHttpServer.getAddress().getPort()) + .path("/old" + path) + .toURL(); + + URI newuri = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(testHttpServer.getAddress().getPort()) + .path("/new" + path) + .build(); + + // check old client + + HttpURLConnection testConnection = (HttpURLConnection) oldurl.openConnection(Proxy.NO_PROXY); + + // Check for successful authentication + int status = testConnection.getResponseCode(); + if (status != 401) { + InputStream is = testConnection.getInputStream(); + while (is.read() != -1) ; + is.close(); + } + if (status != expectedStatus) { + System.err.println("Error (old): " + path); + failCount++; + } + + HttpRequest request = HttpRequest.newBuilder() + .uri(newuri) + .GET() + .build(); + + status = -1; + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.discarding()); + status = response.statusCode(); + } catch (IOException e) { + System.out.println("NEW: " + e); + status = 401; // limitation in new API. + } + if (status != expectedStatus) { + System.err.println("Error (new): " + path); + failCount++; + } + } + + public static void main(String[] args) throws Exception { + clientAuth = new ClientAuthenticator(); + client = HttpClient.newBuilder() + .authenticator(clientAuth) + .build(); + + String defaultCharset = System.getProperty("file.encoding"); + boolean isUTF8 = defaultCharset.equalsIgnoreCase("UTF-8"); + testHandler = new Handler(); + InetSocketAddress addr = new InetSocketAddress(0); + testHttpServer = HttpServer.create(addr, 0); + + // Set the passing credentials OLD client + setAuthenticationPW("/old/test1/", "passingCharset@test.realm", UNICODE_PW, UTF_8); + setAuthenticationPW("/old/test2/", "failingCharset@test.realm", UNICODE_PW, ISO_8859_1); + setAuthenticationPW("/old/test3/", "defaultCharset@test.realm", UNICODE_PW, null); + + // Set the passing credentials NEW client + setAuthenticationPW("/new/test1/", "passingCharset@test.realm", UNICODE_PW, UTF_8); + setAuthenticationPW("/new/test2/", "failingCharset@test.realm", UNICODE_PW, ISO_8859_1); + setAuthenticationPW("/new/test3/", "defaultCharset@test.realm", UNICODE_PW, null); + + ExecutorService executor = Executors.newCachedThreadPool(); + testHttpServer.setExecutor(executor); + testHttpServer.start(); + java.net.Authenticator.setDefault(clientAuth); + + connectAndAuth("/test1/passingCharset.html", 200); + connectAndAuth("/test2/failingCharset.html", 401); + if (isUTF8) { + connectAndAuth("/test3/defaultCharset.html", 200); + } + + testHttpServer.stop(2); + executor.shutdown(); + + // should fail once with UNICODE_PW and unsupporting character set + if (failCount > 0) + throw new RuntimeException("Fail count : " + failCount); + } +} diff -r 4863a802a7c1 -r 0094711309c3 test/jdk/com/sun/net/httpserver/bugs/8199849/ParamTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/com/sun/net/httpserver/bugs/8199849/ParamTest.java Thu Aug 22 09:53:19 2019 -0400 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.net.*; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.*; +import java.nio.charset.StandardCharsets; +import jdk.test.lib.net.URIBuilder; + +/** + * @test + * @bug 8199849 + * @summary + * @library /test/lib + * @run main/othervm ParamTest + * @run main/othervm -Djava.net.preferIPv6Addresses=true ParamTest + */ + +public class ParamTest { + + static final String[] variants = { + " charset=utf-8", + " charset=UtF-8", + " charset=\"utF-8\"", + " charset=\"UtF-8\"" + }; + + static final int LOOPS = variants.length; + + volatile static boolean error = false; + + static class BasicServer extends Thread { + + final ServerSocket server; + + Socket s; + InputStream is; + OutputStream os; + + static final String realm = "wallyworld"; + + String reply1 = "HTTP/1.1 401 Unauthorized\r\n"+ + "WWW-Authenticate: Basic realm=\""+realm+"\"\r\n"; + + String reply2 = "HTTP/1.1 200 OK\r\n"+ + "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" + + "Server: Apache/1.3.14 (Unix)\r\n" + + "Connection: close\r\n" + + "Content-Type: text/html; charset=iso-8859-1\r\n" + + "Content-Length: 10\r\n\r\n"; + + BasicServer(ServerSocket s) { + server = s; + } + + String readHeaders(Socket sock) throws IOException { + InputStream is = sock.getInputStream(); + String s = ""; + byte[] buf = new byte[1024]; + while (!s.endsWith("\r\n\r\n")) { + int c = is.read(buf); + if (c == -1) + return s; + String f = new String(buf, 0, c, StandardCharsets.ISO_8859_1); + s = s + f; + } + return s; + } + + void check(String s, int iteration) { + if (s.indexOf(encodedAuthString) == -1) { + System.err.printf("On iteration %d, wrong auth string received %s\n", iteration, s); + error = true; + } else { + System.err.println("check: correct auth string received"); + } + } + + public void run() { + try { + for (int j = 0; j < 2; j++) + for (int i = 0; i < LOOPS; i++) { + System.out.println("Server 1: accept"); + s = server.accept(); + readHeaders(s); + System.out.println("accepted"); + os = s.getOutputStream(); + String str = reply1 + variants[i] + "\r\n\r\n"; + os.write(str.getBytes()); + + System.out.println("Server 2: accept"); + Socket s1 = server.accept(); + String request = readHeaders(s1); + check(request, i); + System.out.println("accepted"); + os = s1.getOutputStream(); + os.write((reply2 + "HelloWorld").getBytes()); + os.flush(); + s.close(); + s1.close(); + finished(); + } + } catch (Exception e) { + System.out.println(e); + error = true; + } + } + + public synchronized void finished() { + notifyAll(); + } + + } + + static final String password = "Selam D\u00fcnya."; + + // "user : " encoded in UTF-8 and converted to Base 64 + + static final String encodedAuthString = "dXNlcjpTZWxhbSBEw7xueWEu"; + + static class MyAuthenticator extends Authenticator { + MyAuthenticator() { + super(); + } + + public PasswordAuthentication getPasswordAuthentication() + { + System.out.println("Auth called"); + return (new PasswordAuthentication ("user", password.toCharArray())); + } + } + + + static void read(InputStream is) throws IOException { + int c; + System.out.println("reading"); + while ((c=is.read()) != -1) { + System.out.write(c); + } + System.out.println(""); + System.out.println("finished reading"); + } + + public static void main(String args[]) throws Exception { + MyAuthenticator auth = new MyAuthenticator(); + Authenticator.setDefault(auth); + InetAddress loopback = InetAddress.getLoopbackAddress(); + ServerSocket ss = new ServerSocket(); + ss.bind(new InetSocketAddress(loopback, 0)); + int port = ss.getLocalPort(); + BasicServer server = new BasicServer(ss); + synchronized (server) { + server.start(); + System.out.println("client 1"); + String base = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(port) + .path("/") + .build() + .toString(); + URL url = new URL(base + "d1/d2/d3/foo.html"); + + for (int i = 0; i < LOOPS; i++) { + URLConnection urlc = url.openConnection(Proxy.NO_PROXY); + InputStream is = urlc.getInputStream(); + read(is); + System.out.println("Client: waiting for notify"); + server.wait(); + System.out.println("Client: continue"); + // check if authenticator was called once (ok) or twice (not) + if (error) { + System.err.println("Error old client iteration " + i); + } + } + + URI uri = url.toURI(); + HttpClient client = HttpClient.newBuilder() + .authenticator(auth) + .build(); + + HttpRequest request = HttpRequest + .newBuilder(uri) + .GET() + .build(); + + for (int i = 0; i < LOOPS; i++) { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.discarding()); + int status = response.statusCode(); + if (status != 200) { + System.err.printf("Error new client (%d) iteration ", + status, i); + error = true; + } else + System.err.println("New client ok iteration " + i); + System.out.println("New Client: waiting for notify"); + server.wait(); + System.out.println("New Client: continue"); + } + + if (error) { + throw new RuntimeException("Test failed"); + } + } + } +} diff -r 4863a802a7c1 -r 0094711309c3 test/jdk/com/sun/net/httpserver/bugs/8199849/TestHttpUnicode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/com/sun/net/httpserver/bugs/8199849/TestHttpUnicode.java Thu Aug 22 09:53:19 2019 -0400 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8199849 + * @library /test/lib + * @summary Checks that unicode bytes are being handled correctly + * @run main/othervm -Dfile.encoding=UTF_8 TestHttpUnicode + */ + +import com.sun.net.httpserver.*; +import jdk.test.lib.net.URIBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.net.*; + +public class TestHttpUnicode { + + private static final String TEST_USER = "Selam D\u00fcnya. Ho\u015f\u00e7akal D\u00fcnya"; + private static final String TEST_PW = "Selam D\u00fcnya. Ho\u015f\u00e7akal D\u00fcnya"; + + static class ClientAuthenticator extends java.net.Authenticator { + public PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(TEST_USER, TEST_PW.toCharArray()); + } + } + + static class Handler implements HttpHandler { + public void handle(HttpExchange t) throws IOException { + InputStream is = t.getRequestBody(); + while (is.read() != -1) ; + is.close(); + + HttpPrincipal p = t.getPrincipal(); + if (p.getUsername().equals(TEST_USER)) { + t.sendResponseHeaders(200, -1); + } + t.close(); + } + } + + public static void main(String[] args) throws Exception { + HttpServer testHttpServer = null; + try { + InetSocketAddress loopbackAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + testHttpServer = HttpServer.create(loopbackAddress, 0); + HttpContext context = testHttpServer.createContext("/test", new Handler()); + System.setProperty("http.maxRedirects", "3"); + + BasicAuthenticator serverAuthenticator = new BasicAuthenticator("authCharacterSet@test.realm") { + public boolean checkCredentials(String username, String pw) { + return username.equals(TEST_USER) && pw.equals(TEST_PW); + } + }; + context.setAuthenticator(serverAuthenticator); + java.net.Authenticator.setDefault(new ClientAuthenticator()); + + testHttpServer.start(); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(testHttpServer.getAddress().getPort()) + .path("/test/authCharacterSet.html") + .toURL(); + HttpURLConnection testConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + + // Authenication CHECK + if (testConnection.getResponseCode() == 401) { + throw new RuntimeException("Test Authentication failed with HTTP Status 401."); + } + + InputStream is = testConnection.getInputStream(); + while (is.read() != -1) ; + } finally { + testHttpServer.stop(2); + } + } +} diff -r 4863a802a7c1 -r 0094711309c3 test/jdk/java/net/Socks/SocksIPv6Test.java --- a/test/jdk/java/net/Socks/SocksIPv6Test.java Thu Aug 22 09:51:36 2019 -0400 +++ b/test/jdk/java/net/Socks/SocksIPv6Test.java Thu Aug 22 09:53:19 2019 -0400 @@ -24,6 +24,7 @@ /* @test * @bug 7100957 * @modules jdk.httpserver + * @library /test/lib * @summary Java doesn't correctly handle the SOCKS protocol when used over IPv6. * @run testng SocksIPv6Test */ @@ -46,10 +47,13 @@ import java.util.List; import com.sun.net.httpserver.*; import java.io.BufferedWriter; +import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import jdk.test.lib.NetworkConfiguration; + import static org.testng.Assert.*; public class SocksIPv6Test { @@ -57,11 +61,13 @@ private HttpServer server; private SocksServer socks; private String response = "Hello."; - private static boolean shouldRun = false; @BeforeClass public void setUp() throws Exception { - shouldRun = ensureInet6AddressFamily() && ensureIPv6OnLoopback(); + if (!ensureInet6AddressFamily() || !ensureIPv6OnLoopback()) { + NetworkConfiguration.printSystemConfiguration(System.out); + throw new SkipException("Host does not support IPv6"); + } server = HttpServer.create(new InetSocketAddress("::1", 0), 0); server.createContext("/", ex -> { @@ -120,8 +126,6 @@ @Test(groups = "unit") public void testSocksOverIPv6() throws Exception { - if (!shouldRun) return; - Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("::1", socks.getPort())); URL url = new URL("http://[::1]:" + server.getAddress().getPort()); @@ -136,8 +140,6 @@ @Test(groups = "unit") public void testSocksOverIPv6Hostname() throws Exception { - if (!shouldRun) return; - InetAddress ipv6Loopback = InetAddress.getByName("::1"); String ipv6Hostname = ipv6Loopback.getHostName(); String ipv6HostAddress = ipv6Loopback.getHostAddress();