Compare commits

...

48 Commits

Author SHA1 Message Date
Antonio Vieiro
1c80800a26 8340552: Harden TzdbZoneRulesCompiler against missing zone names
Reviewed-by: andrew
Backport-of: d70ea49243
2024-11-29 11:48:25 +00:00
RadekCap
874b25e641 8339637: (tz) Update Timezone Data to 2024b
Reviewed-by: andrew
Backport-of: fbc040cf8a
2024-11-27 22:22:24 +00:00
Antonio Vieiro
2155f8d22a 8339803: Acknowledge case insensitive unambiguous keywords in tzdata files
Reviewed-by: andrew
Backport-of: 0d7b2729e4
2024-11-27 14:54:06 +00:00
Andrew John Hughes
c99638d35c 8335801: [11u] Backport of 8210988 to 11u removes gcc warnings
Reviewed-by: phh
2024-11-13 00:57:51 +00:00
Daniel Hu
513a67a65f 8303920: Avoid calling out to python in DataDescriptorSignatureMissing test
Reviewed-by: andrew
Backport-of: 79349b8bb3
2024-11-12 21:57:00 +00:00
Jiří Vaněk
cf53387daf 8342629: [11u] Properly message out that shenandoah is disabled
Reviewed-by: andrew
2024-11-11 13:53:37 +00:00
Amos Shi
249144c02b 8225045: javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java fails on linux-x64
Backport-of: a483869a6a
2024-11-11 05:57:56 +00:00
Amos Shi
04e6f37d2c 8247706: Unintentional use of new Date(year...) with absolute year
Backport-of: 175b597ad2
2024-11-11 05:56:53 +00:00
Amos Shi
add90003d6 8232367: Update Reactive Streams to 1.0.3 -- tests only
Backport-of: 9f6af13f9d
2024-11-11 05:55:16 +00:00
Dan Lutker
827528c322 8339470: [17u] More defensive fix for 8163921
Backport-of: 6261dd7e38
2024-11-08 18:23:05 +00:00
SendaoYan
96805ae97b 8224624: Inefficiencies in CodeStrings::add_comment cause timeouts
Changing CodeStrings to a doubly-linked-list and searching for the comment with the right offset in reverse.

Backport-of: 7cff981f5a
2024-11-08 15:25:04 +00:00
SendaoYan
98161b7a9b 8334332: TestIOException.java fails if run by root
Reviewed-by: phh
Backport-of: 472b935b44
2024-11-04 23:32:46 +00:00
SendaoYan
9bf55020f0 8342426: [11u] javax/naming/module/RunBasic.java javac compile fails
Reviewed-by: andrew
2024-10-30 17:37:56 +00:00
Goetz Lindenmaier
8ba0341757 Merge 2024-10-16 11:34:10 +00:00
Andrew John Hughes
cee8535a9d 8341675: [11u] Remove designator DEFAULT_PROMOTED_VERSION_PRE=ea for release 11.0.25
Reviewed-by: clanger
2024-10-10 16:24:35 +02:00
Sergey Bylokhov
1393271305 8251188: Update LDAP tests not to use wildcard addresses
Reviewed-by: mbalao, andrew
Backport-of: a75edc29c6
2024-10-07 06:13:44 +00:00
Francisco Ferrari Bihurriet
86d5188b89 8332644: Improve graph optimizations
Reviewed-by: mbalao, andrew
Backport-of: 7c16d649a8118d2e7ee77cedba87e620c83294b4
2024-10-05 15:31:16 +02:00
Sergey Bylokhov
34a77a471b 8290367: Update default value and extend the scope of com.sun.jndi.ldap.object.trustSerialData system property
8332643: Better Location requests

Reviewed-by: yan, andrew
Backport-of: 7765942aee
2024-10-05 15:21:55 +02:00
Sergey Bylokhov
eb960ff6d4 8251188: Update LDAP tests not to use wildcard addresses
Reviewed-by: mbalao, andrew
Backport-of: a75edc29c6
2024-10-05 15:11:15 +02:00
Sergey Bylokhov
bd85b8729d 8211920: Close server socket and cleanups in test/jdk/javax/naming/module/RunBasic.java
Reviewed-by: yan, andrew
Backport-of: e61252dc27
2024-10-05 15:08:22 +02:00
Alexei Voitylov
56ded02fd8 8331446: Improve deserialization support
Reviewed-by: yan, mbalao, andrew
Backport-of: 8e4a392832f83e16d521024505b52c96d0a993f2
2024-10-05 14:37:24 +02:00
Alexey Bakhtin
51657d990a 8328726: Better Kerberos support
Reviewed-by: mbalao
Backport-of: 7325899a11f17bf4516d39495a12796385e459ed
2024-10-04 07:02:05 +02:00
Martin Balao
d73c162a85 8335713: Enhance vectorization analysis
Reviewed-by: roland
Backport-of: 3c05ad2290936ec9abc3f271cb6bf89e18c3eea7
2024-10-03 22:21:25 +02:00
Martin Balao
6ae4b326fa 8328544: Improve handling of vectorization
Reviewed-by: roland, yan
Backport-of: b5174c9159fbffdf335ee6835267ba0e674cf432
2024-10-03 22:04:12 +02:00
Alexey Bakhtin
2d393d8bb4 8328286: Enhance HTTP client
Reviewed-by: mbalao
Backport-of: cf8dc79f392c8ec3414d8b36803f026852c4e386
2024-10-03 21:53:21 +02:00
Alexey Bakhtin
68c131d590 8284585: PushPromiseContinuation test fails intermittently in timeout
Reviewed-by: mbalao
Backport-of: 65da38d844
2024-10-03 21:53:21 +02:00
Alexey Bakhtin
fe9c9c707b 8303965: java.net.http.HttpClient should reset the stream if response headers contain malformed header fields
Reviewed-by: mbalao
Backport-of: 466ffebcae
2024-10-03 21:53:21 +02:00
Alexey Bakhtin
445e79ea99 8263031: HttpClient throws Exception if it receives a Push Promise that is too large
Reviewed-by: mbalao
Backport-of: 4d2cd26ab5
2024-10-03 21:53:21 +02:00
Alexey Bakhtin
240b296234 8307383: Enhance DTLS connections
Reviewed-by: mbaesken, andrew
Backport-of: 362dbbaa952b3d4a5270c6bfae879a12e9bdf4d1
2024-10-03 21:53:21 +02:00
Antonio Vieiro
a754a3d897 8339644: Improve parsing of Day/Month in tzdata rules
Backport-of: 5faa0df6fb
2024-10-02 19:38:28 +00:00
Goetz Lindenmaier
6436749891 Merge 2024-10-02 08:26:50 +00:00
Goetz Lindenmaier
82c330b464 8341059: Change Entrust TLS distrust date to November 12, 2024
Backport-of: eced83e130
2024-10-01 13:37:14 +00:00
Goetz Lindenmaier
217b9fdf05 8341057: Add 2 SSL.com TLS roots
Reviewed-by: mbaesken
Backport-of: 824a297aae
2024-10-01 13:34:57 +00:00
Zdenek Zambersky
2232d1f7b4 8338402: GHA: some of bundles may not get removed
Backport-of: d8e4d3f2d6
2024-09-30 16:23:40 +00:00
Antonio
06d87ca659 8299254: Support dealing with standard assert macro
Reviewed-by: sgehwolf
Backport-of: 89dd23f2fa
2024-09-30 16:03:42 +00:00
Daniel Hu
015796747f 8316193: jdk/jfr/event/oldobject/TestListenerLeak.java java.lang.Exception: Could not find leak
Backport-of: f6be922952
2024-09-30 16:01:52 +00:00
Sergey Bylokhov
bec83f35d6 8211920: Close server socket and cleanups in test/jdk/javax/naming/module/RunBasic.java
Reviewed-by: yan, andrew
Backport-of: e61252dc27
2024-09-30 15:45:40 +00:00
George Adams
59b3859160 8340815: Add SECURITY.md file
Backport-of: 0474f020bf
2024-09-30 13:00:44 +00:00
Antonio
dd35f187fd 8340671: GHA: Bump macOS and Xcode versions to macos-12 and XCode 13.4.1
Reviewed-by: sgehwolf
2024-09-26 08:31:17 +00:00
Goetz Lindenmaier
b2d385978f Merge 2024-09-25 08:06:18 +00:00
Alexey Bakhtin
0358cbd0a1 8296410: HttpClient throws java.io.IOException: no statuscode in response for HTTP2
Reviewed-by: goetz
Backport-of: f4b140b420
2024-09-23 14:08:45 +00:00
Goetz Lindenmaier
934decc147 Merge 2024-09-11 09:18:16 +00:00
Goetz Lindenmaier
90ad5b18de 8337664: Distrust TLS server certificates issued after Oct 2024 and anchored by Entrust Root CAs
Reviewed-by: phh
Backport-of: 7d49c52272
2024-09-08 12:34:28 +00:00
Goetz Lindenmaier
6ee8bacfdd 8338139: {ClassLoading,Memory}MXBean::isVerbose methods are inconsistent with their setVerbose methods
Reviewed-by: phh
Backport-of: 897f433b33
2024-09-05 09:56:35 +00:00
Andrew Lu
ffcdc10405 8315936: Parallelize gc/stress/TestStressG1Humongous.java test
Backport-of: 3f19df685c
2024-09-02 02:24:26 +00:00
Andrew Lu
76b8327ba0 8328642: Convert applet test MouseDraggedOutCauseScrollingTest.html to main
Reviewed-by: mbaesken
Backport-of: ab183e437c
2024-09-02 02:24:11 +00:00
Andrew Lu
8c31358ccc 8328300: Convert PrintDialogsTest.java from Applet to main program
Reviewed-by: mbaesken
Backport-of: dea94f4445
2024-09-02 02:23:53 +00:00
Goetz Lindenmaier
ce572dfede 8339082: Bump update version for OpenJDK: jdk-11.0.26
Reviewed-by: sgehwolf
2024-08-28 10:25:28 +00:00
148 changed files with 7625 additions and 2521 deletions

View File

@@ -55,7 +55,7 @@ on:
jobs:
build-macos:
name: build
runs-on: macos-13
runs-on: macos-12
strategy:
fail-fast: false

View File

@@ -223,7 +223,7 @@ jobs:
uses: ./.github/workflows/build-macos.yml
with:
platform: macos-x64
xcode-toolset-version: '14.3.1'
xcode-toolset-version: '13.4.1'
configure-arguments: ${{ github.event.inputs.configure-arguments }}
make-arguments: ${{ github.event.inputs.make-arguments }}
if: needs.select.outputs.macos-x64 == 'true'
@@ -234,7 +234,7 @@ jobs:
uses: ./.github/workflows/build-macos.yml
with:
platform: macos-aarch64
xcode-toolset-version: '14.3.1'
xcode-toolset-version: '13.4.1'
extra-conf-options: '--openjdk-target=aarch64-apple-darwin'
configure-arguments: ${{ github.event.inputs.configure-arguments }}
make-arguments: ${{ github.event.inputs.make-arguments }}
@@ -298,7 +298,7 @@ jobs:
with:
platform: macos-x64
bootjdk-platform: macos-x64
runs-on: macos-13
runs-on: macos-12
test-windows-x64:
name: windows-x64
@@ -341,7 +341,7 @@ jobs:
-H 'Accept: application/vnd.github+json' \
-H 'Authorization: Bearer ${{ github.token }}' \
-H 'X-GitHub-Api-Version: 2022-11-28' \
'${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts')"
'${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts?per_page=100')"
BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')"
for id in $BUNDLE_ARTIFACT_IDS; do
echo "Removing $id"

View File

@@ -127,7 +127,7 @@ jobs:
run: |
# On macOS we need to install some dependencies for testing
brew install make
sudo xcode-select --switch /Applications/Xcode_14.3.1.app/Contents/Developer
sudo xcode-select --switch /Applications/Xcode_13.4.1.app/Contents/Developer
# This will make GNU make available as 'make' and not only as 'gmake'
echo '/usr/local/opt/make/libexec/gnubin' >> $GITHUB_PATH
if: runner.os == 'macOS'

View File

@@ -1,7 +1,7 @@
[general]
project=jdk-updates
jbs=JDK
version=11.0.25
version=11.0.26
[checks]
error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists

3
SECURITY.md Normal file
View File

@@ -0,0 +1,3 @@
# JDK Vulnerabilities
Please follow the process outlined in the [OpenJDK Vulnerability Policy](https://openjdk.org/groups/vulnerability/report) to disclose vulnerabilities in the JDK.

View File

@@ -192,6 +192,12 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
DISABLE_WARNING_PREFIX="-Wno-"
BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-"
CFLAGS_WARNINGS_ARE_ERRORS="-Werror"
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2"
WARNINGS_ENABLE_ADDITIONAL_JVM="-Wpointer-arith -Wsign-compare -Wunused-function -Wundef -Wunused-value -Woverloaded-virtual -Wreturn-type"
DISABLED_WARNINGS="unused-parameter unused"
;;
clang)
@@ -200,7 +206,7 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
CFLAGS_WARNINGS_ARE_ERRORS="-Werror"
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2"
WARNINGS_ENABLE_ADDITIONAL_JVM="-Wpointer-arith -Wsign-compare -Wunused-function -Wundef -Wunused-value -Woverloaded-virtual -Wreorder"
WARNINGS_ENABLE_ADDITIONAL_JVM="-Wpointer-arith -Wsign-compare -Wunused-function -Wundef -Wunused-value -Woverloaded-virtual"
DISABLED_WARNINGS="unused-parameter unused"
;;

View File

@@ -378,6 +378,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
fi
else
DISABLED_JVM_FEATURES="$DISABLED_JVM_FEATURES shenandoahgc"
AC_MSG_RESULT([no, must be manually enabled --with-jvm-features=shenandoahgc])
fi
# Only enable ZGC on supported platforms

View File

@@ -28,12 +28,12 @@
DEFAULT_VERSION_FEATURE=11
DEFAULT_VERSION_INTERIM=0
DEFAULT_VERSION_UPDATE=25
DEFAULT_VERSION_UPDATE=26
DEFAULT_VERSION_PATCH=0
DEFAULT_VERSION_EXTRA1=0
DEFAULT_VERSION_EXTRA2=0
DEFAULT_VERSION_EXTRA3=0
DEFAULT_VERSION_DATE=2024-10-15
DEFAULT_VERSION_DATE=2025-01-21
DEFAULT_VERSION_CLASSFILE_MAJOR=55 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11"

View File

@@ -0,0 +1,21 @@
Owner: CN=SSL.com TLS ECC Root CA 2022, O=SSL Corporation, C=US
Issuer: CN=SSL.com TLS ECC Root CA 2022, O=SSL Corporation, C=US
Serial number: 1403f5abfb378b17405be243b2a5d1c4
Valid from: Thu Aug 25 16:33:48 GMT 2022 until: Sun Aug 19 16:33:47 GMT 2046
Signature algorithm name: SHA384withECDSA
Subject Public Key Algorithm: 384-bit EC (secp384r1) key
Version: 3
-----BEGIN CERTIFICATE-----
MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw
CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT
U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2
MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh
dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm
acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN
SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW
uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp
15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN
b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,39 @@
Owner: CN=SSL.com TLS RSA Root CA 2022, O=SSL Corporation, C=US
Issuer: CN=SSL.com TLS RSA Root CA 2022, O=SSL Corporation, C=US
Serial number: 6fbedaad73bd0840e28b4dbed4f75b91
Valid from: Thu Aug 25 16:34:22 GMT 2022 until: Sun Aug 19 16:34:21 GMT 2046
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3
-----BEGIN CERTIFICATE-----
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP
L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY
t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins
S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3
PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO
L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3
R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w
dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS
+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS
d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG
AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f
gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z
NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM
QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf
R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ
DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW
P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy
lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq
bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w
AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q
r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji
Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
-----END CERTIFICATE-----

View File

@@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
tzdata2024a
tzdata2024b

View File

@@ -126,17 +126,16 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 16
# Cape Verde / Cabo Verde
#
# From Paul Eggert (2018-02-16):
# Shanks gives 1907 for the transition to +02.
# For now, ignore that and follow the 1911-05-26 Portuguese decree
# (see Europe/Lisbon).
# From Tim Parenti (2024-07-01), per Paul Eggert (2018-02-16):
# For timestamps before independence, see commentary for Europe/Lisbon.
# Shanks gives 1907 instead for the transition to -02.
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia
-2:00 - -02 1942 Sep
-2:00 1:00 -01 1945 Oct 15
-2:00 - -02 1975 Nov 25 2:00
-1:00 - -01
-2:00 - %z 1942 Sep
-2:00 1:00 %z 1945 Oct 15
-2:00 - %z 1975 Nov 25 2:00
-1:00 - %z
# Chad
# Zone NAME STDOFF RULES FORMAT [UNTIL]
@@ -368,14 +367,12 @@ Zone Africa/Cairo 2:05:09 - LMT 1900 Oct
# Guinea-Bissau
#
# From Paul Eggert (2018-02-16):
# Shanks gives 1911-05-26 for the transition to WAT,
# evidently confusing the date of the Portuguese decree
# (see Europe/Lisbon) with the date that it took effect.
# From Tim Parenti (2024-07-01), per Paul Eggert (2018-02-16):
# For timestamps before independence, see commentary for Europe/Lisbon.
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u
-1:00 - -01 1975
-1:00 - %z 1975
0:00 - GMT
# Comoros
@@ -440,10 +437,10 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Africa/Nairobi 2:27:16 - LMT 1908 May
2:30 - +0230 1928 Jun 30 24:00
2:30 - %z 1928 Jun 30 24:00
3:00 - EAT 1930 Jan 4 24:00
2:30 - +0230 1936 Dec 31 24:00
2:45 - +0245 1942 Jul 31 24:00
2:30 - %z 1936 Dec 31 24:00
2:45 - %z 1942 Jul 31 24:00
3:00 - EAT
# Liberia
@@ -614,7 +611,7 @@ Rule Mauritius 2008 only - Oct lastSun 2:00 1:00 -
Rule Mauritius 2009 only - Mar lastSun 2:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis
4:00 Mauritius +04/+05
4:00 Mauritius %z
# Agalega Is, Rodriguez
# no information; probably like Indian/Mauritius
@@ -1094,10 +1091,10 @@ Rule Morocco 2087 only - May 11 2:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26
0:00 Morocco +00/+01 1984 Mar 16
1:00 - +01 1986
0:00 Morocco +00/+01 2018 Oct 28 3:00
1:00 Morocco +01/+00
0:00 Morocco %z 1984 Mar 16
1:00 - %z 1986
0:00 Morocco %z 2018 Oct 28 3:00
1:00 Morocco %z
# Western Sahara
#
@@ -1111,9 +1108,9 @@ Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26
# since most of it was then controlled by Morocco.
Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún
-1:00 - -01 1976 Apr 14
0:00 Morocco +00/+01 2018 Oct 28 3:00
1:00 Morocco +01/+00
-1:00 - %z 1976 Apr 14
0:00 Morocco %z 2018 Oct 28 3:00
1:00 Morocco %z
# Botswana
# Burundi
@@ -1124,13 +1121,27 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún
# Zambia
# Zimbabwe
#
# Shanks gives 1903-03-01 for the transition to CAT.
# Perhaps the 1911-05-26 Portuguese decree
# https://dre.pt/pdf1sdip/1911/05/12500/23132313.pdf
# merely made it official?
# From Tim Parenti (2024-07-01):
# For timestamps before Mozambique's independence, see commentary for
# Europe/Lisbon.
#
# From Paul Eggert (2024-05-24):
# The London Gazette, 1903-04-03, page 2245, says that
# as of 1903-03-03 a time ball at the port of Lourenço Marques
# (as Maputo was then called) was dropped daily at 13:00:00 LMT,
# corresponding to 22:49:41.7 GMT, so local time was +02:10:18.3.
# Conversely, the newspaper South Africa, 1909-02-09, page 321,
# says the port had just installed an apparatus that communicated
# "from the controlling clock in the new Observatory at Reuben Point ...
# exact mean South African time, i.e., 30 deg., or 2 hours East of Greenwich".
# Although Shanks gives 1903-03-01 for the transition to CAT,
# evidently the port transitioned to CAT after 1903-03-03 but before
# the Portuguese legal transition of 1912-01-01 (see Europe/Lisbon commentary).
# For lack of better info, list 1909 as the transition date.
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Africa/Maputo 2:10:20 - LMT 1903 Mar
#STDOFF 2:10:18.3
Zone Africa/Maputo 2:10:18 - LMT 1909
2:00 - CAT
# Namibia
@@ -1195,7 +1206,7 @@ Rule Namibia 1995 2017 - Apr Sun>=1 2:00 -1:00 WAT
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8
1:30 - +0130 1903 Mar
1:30 - %z 1903 Mar
2:00 - SAST 1942 Sep 20 2:00
2:00 1:00 SAST 1943 Mar 21 2:00
2:00 - SAST 1990 Mar 21 # independence
@@ -1283,7 +1294,7 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8
Zone Africa/Lagos 0:13:35 - LMT 1905 Jul 1
0:00 - GMT 1908 Jul 1
0:13:35 - LMT 1914 Jan 1
0:30 - +0030 1919 Sep 1
0:30 - %z 1919 Sep 1
1:00 - WAT
# São Tomé and Príncipe

View File

@@ -110,34 +110,34 @@
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Casey 0 - -00 1969
8:00 - +08 2009 Oct 18 2:00
11:00 - +11 2010 Mar 5 2:00
8:00 - +08 2011 Oct 28 2:00
11:00 - +11 2012 Feb 21 17:00u
8:00 - +08 2016 Oct 22
11:00 - +11 2018 Mar 11 4:00
8:00 - +08 2018 Oct 7 4:00
11:00 - +11 2019 Mar 17 3:00
8:00 - +08 2019 Oct 4 3:00
11:00 - +11 2020 Mar 8 3:00
8:00 - +08 2020 Oct 4 0:01
11:00 - +11 2021 Mar 14 0:00
8:00 - +08 2021 Oct 3 0:01
11:00 - +11 2022 Mar 13 0:00
8:00 - +08 2022 Oct 2 0:01
11:00 - +11 2023 Mar 9 3:00
8:00 - +08
8:00 - %z 2009 Oct 18 2:00
11:00 - %z 2010 Mar 5 2:00
8:00 - %z 2011 Oct 28 2:00
11:00 - %z 2012 Feb 21 17:00u
8:00 - %z 2016 Oct 22
11:00 - %z 2018 Mar 11 4:00
8:00 - %z 2018 Oct 7 4:00
11:00 - %z 2019 Mar 17 3:00
8:00 - %z 2019 Oct 4 3:00
11:00 - %z 2020 Mar 8 3:00
8:00 - %z 2020 Oct 4 0:01
11:00 - %z 2021 Mar 14 0:00
8:00 - %z 2021 Oct 3 0:01
11:00 - %z 2022 Mar 13 0:00
8:00 - %z 2022 Oct 2 0:01
11:00 - %z 2023 Mar 9 3:00
8:00 - %z
Zone Antarctica/Davis 0 - -00 1957 Jan 13
7:00 - +07 1964 Nov
7:00 - %z 1964 Nov
0 - -00 1969 Feb
7:00 - +07 2009 Oct 18 2:00
5:00 - +05 2010 Mar 10 20:00u
7:00 - +07 2011 Oct 28 2:00
5:00 - +05 2012 Feb 21 20:00u
7:00 - +07
7:00 - %z 2009 Oct 18 2:00
5:00 - %z 2010 Mar 10 20:00u
7:00 - %z 2011 Oct 28 2:00
5:00 - %z 2012 Feb 21 20:00u
7:00 - %z
Zone Antarctica/Mawson 0 - -00 1954 Feb 13
6:00 - +06 2009 Oct 18 2:00
5:00 - +05
6:00 - %z 2009 Oct 18 2:00
5:00 - %z
# References:
# Casey Weather (1998-02-26)
# http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html
@@ -313,10 +313,10 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Vostok 0 - -00 1957 Dec 16
7:00 - +07 1994 Feb
7:00 - %z 1994 Feb
0 - -00 1994 Nov
7:00 - +07 2023 Dec 18 2:00
5:00 - +05
7:00 - %z 2023 Dec 18 2:00
5:00 - %z
# S Africa - year-round bases
# Marion Island, -4653+03752
@@ -349,7 +349,7 @@ Zone Antarctica/Vostok 0 - -00 1957 Dec 16
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Rothera 0 - -00 1976 Dec 1
-3:00 - -03
-3:00 - %z
# Uruguay - year round base
# Artigas, King George Island, -621104-0585107

View File

@@ -106,8 +106,8 @@ Rule RussiaAsia 1996 2010 - Oct lastSun 2:00s 0 -
# Afghanistan
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Kabul 4:36:48 - LMT 1890
4:00 - +04 1945
4:30 - +0430
4:00 - %z 1945
4:30 - %z
# Armenia
# From Paul Eggert (2006-03-22):
@@ -139,12 +139,12 @@ Rule Armenia 2011 only - Mar lastSun 2:00s 1:00 -
Rule Armenia 2011 only - Oct lastSun 2:00s 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Yerevan 2:58:00 - LMT 1924 May 2
3:00 - +03 1957 Mar
4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s
3:00 RussiaAsia +03/+04 1995 Sep 24 2:00s
4:00 - +04 1997
4:00 RussiaAsia +04/+05 2011
4:00 Armenia +04/+05
3:00 - %z 1957 Mar
4:00 RussiaAsia %z 1991 Mar 31 2:00s
3:00 RussiaAsia %z 1995 Sep 24 2:00s
4:00 - %z 1997
4:00 RussiaAsia %z 2011
4:00 Armenia %z
# Azerbaijan
@@ -165,12 +165,12 @@ Rule Azer 1997 2015 - Mar lastSun 4:00 1:00 -
Rule Azer 1997 2015 - Oct lastSun 5:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Baku 3:19:24 - LMT 1924 May 2
3:00 - +03 1957 Mar
4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s
3:00 RussiaAsia +03/+04 1992 Sep lastSun 2:00s
4:00 - +04 1996
4:00 EUAsia +04/+05 1997
4:00 Azer +04/+05
3:00 - %z 1957 Mar
4:00 RussiaAsia %z 1991 Mar 31 2:00s
3:00 RussiaAsia %z 1992 Sep lastSun 2:00s
4:00 - %z 1996
4:00 EUAsia %z 1997
4:00 Azer %z
# Bangladesh
# From Alexander Krivenyshev (2009-05-13):
@@ -251,17 +251,17 @@ Rule Dhaka 2009 only - Dec 31 24:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Dhaka 6:01:40 - LMT 1890
5:53:20 - HMT 1941 Oct # Howrah Mean Time?
6:30 - +0630 1942 May 15
5:30 - +0530 1942 Sep
6:30 - +0630 1951 Sep 30
6:00 - +06 2009
6:00 Dhaka +06/+07
6:30 - %z 1942 May 15
5:30 - %z 1942 Sep
6:30 - %z 1951 Sep 30
6:00 - %z 2009
6:00 Dhaka %z
# Bhutan
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu
5:30 - +0530 1987 Oct
6:00 - +06
5:30 - %z 1987 Oct
6:00 - %z
# British Indian Ocean Territory
# Whitman and the 1995 CIA time zone map say 5:00, but the
@@ -271,8 +271,8 @@ Zone Asia/Thimphu 5:58:36 - LMT 1947 Aug 15 # or Thimbu
# then contained the Chagos Archipelago).
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Indian/Chagos 4:49:40 - LMT 1907
5:00 - +05 1996
6:00 - +06
5:00 - %z 1996
6:00 - %z
# Cocos (Keeling) Islands
# Myanmar (Burma)
@@ -288,9 +288,9 @@ Zone Indian/Chagos 4:49:40 - LMT 1907
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Yangon 6:24:47 - LMT 1880 # or Rangoon
6:24:47 - RMT 1920 # Rangoon local time
6:30 - +0630 1942 May
9:00 - +09 1945 May 3
6:30 - +0630
6:30 - %z 1942 May
9:00 - %z 1945 May 3
6:30 - %z
# China
@@ -679,7 +679,7 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901
# Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi
# / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.)
Zone Asia/Urumqi 5:50:20 - LMT 1928
6:00 - +06
6:00 - %z
# Hong Kong
@@ -1137,7 +1137,7 @@ Rule Macau 1979 only - Oct Sun>=16 03:30 0 S
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Macau 7:34:10 - LMT 1904 Oct 30
8:00 - CST 1941 Dec 21 23:00
9:00 Macau +09/+10 1945 Sep 30 24:00
9:00 Macau %z 1945 Sep 30 24:00
8:00 Macau C%sT
@@ -1180,7 +1180,7 @@ Zone Asia/Nicosia 2:13:28 - LMT 1921 Nov 14
Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14
2:00 Cyprus EE%sT 1998 Sep
2:00 EUAsia EE%sT 2016 Sep 8
3:00 - +03 2017 Oct 29 1:00u
3:00 - %z 2017 Oct 29 1:00u
2:00 EUAsia EE%sT
# Georgia
@@ -1221,18 +1221,25 @@ Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Tbilisi 2:59:11 - LMT 1880
2:59:11 - TBMT 1924 May 2 # Tbilisi Mean Time
3:00 - +03 1957 Mar
4:00 RussiaAsia +04/+05 1991 Mar 31 2:00s
3:00 RussiaAsia +03/+04 1992
3:00 E-EurAsia +03/+04 1994 Sep lastSun
4:00 E-EurAsia +04/+05 1996 Oct lastSun
4:00 1:00 +05 1997 Mar lastSun
4:00 E-EurAsia +04/+05 2004 Jun 27
3:00 RussiaAsia +03/+04 2005 Mar lastSun 2:00
4:00 - +04
3:00 - %z 1957 Mar
4:00 RussiaAsia %z 1991 Mar 31 2:00s
3:00 RussiaAsia %z 1992
3:00 E-EurAsia %z 1994 Sep lastSun
4:00 E-EurAsia %z 1996 Oct lastSun
4:00 1:00 %z 1997 Mar lastSun
4:00 E-EurAsia %z 2004 Jun 27
3:00 RussiaAsia %z 2005 Mar lastSun 2:00
4:00 - %z
# East Timor
# From Tim Parenti (2024-07-01):
# The 1912-01-01 transition occurred at 00:00 new time, per the 1911-05-24
# Portuguese decree (see Europe/Lisbon). A provision in article 5(c) of the
# decree prescribed that Timor "will keep counting time in harmony with
# neighboring foreign colonies, [for] as long as they do not adopt the time
# that belongs to them in [the Washington Convention] system."
# See Indonesia for the 1945 transition.
# From João Carrascalão, brother of the former governor of East Timor, in
@@ -1256,11 +1263,11 @@ Zone Asia/Tbilisi 2:59:11 - LMT 1880
# midnight on Saturday, September 16.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Dili 8:22:20 - LMT 1912 Jan 1
8:00 - +08 1942 Feb 21 23:00
9:00 - +09 1976 May 3
8:00 - +08 2000 Sep 17 0:00
9:00 - +09
Zone Asia/Dili 8:22:20 - LMT 1911 Dec 31 16:00u
8:00 - %z 1942 Feb 21 23:00
9:00 - %z 1976 May 3
8:00 - %z 2000 Sep 17 0:00
9:00 - %z
# India
@@ -1326,9 +1333,9 @@ Zone Asia/Kolkata 5:53:28 - LMT 1854 Jun 28 # Kolkata
5:53:20 - HMT 1870 # Howrah Mean Time?
5:21:10 - MMT 1906 Jan 1 # Madras local time
5:30 - IST 1941 Oct
5:30 1:00 +0630 1942 May 15
5:30 1:00 %z 1942 May 15
5:30 - IST 1942 Sep
5:30 1:00 +0630 1945 Oct 15
5:30 1:00 %z 1945 Oct 15
5:30 - IST
# Since 1970 the following are like Asia/Kolkata:
# Andaman Is
@@ -1380,33 +1387,33 @@ Zone Asia/Jakarta 7:07:12 - LMT 1867 Aug 10
# Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
# but this must be a typo.
7:07:12 - BMT 1923 Dec 31 16:40u # Batavia
7:20 - +0720 1932 Nov
7:30 - +0730 1942 Mar 23
9:00 - +09 1945 Sep 23
7:30 - +0730 1948 May
8:00 - +08 1950 May
7:30 - +0730 1964
7:20 - %z 1932 Nov
7:30 - %z 1942 Mar 23
9:00 - %z 1945 Sep 23
7:30 - %z 1948 May
8:00 - %z 1950 May
7:30 - %z 1964
7:00 - WIB
# west and central Borneo
Zone Asia/Pontianak 7:17:20 - LMT 1908 May
7:17:20 - PMT 1932 Nov # Pontianak MT
7:30 - +0730 1942 Jan 29
9:00 - +09 1945 Sep 23
7:30 - +0730 1948 May
8:00 - +08 1950 May
7:30 - +0730 1964
7:30 - %z 1942 Jan 29
9:00 - %z 1945 Sep 23
7:30 - %z 1948 May
8:00 - %z 1950 May
7:30 - %z 1964
8:00 - WITA 1988 Jan 1
7:00 - WIB
# Sulawesi, Lesser Sundas, east and south Borneo
Zone Asia/Makassar 7:57:36 - LMT 1920
7:57:36 - MMT 1932 Nov # Macassar MT
8:00 - +08 1942 Feb 9
9:00 - +09 1945 Sep 23
8:00 - %z 1942 Feb 9
9:00 - %z 1945 Sep 23
8:00 - WITA
# Maluku Islands, West Papua, Papua
Zone Asia/Jayapura 9:22:48 - LMT 1932 Nov
9:00 - +09 1944 Sep 1
9:30 - +0930 1964
9:00 - %z 1944 Sep 1
9:30 - %z 1964
9:00 - WIT
# Iran
@@ -1642,9 +1649,9 @@ Rule Iran 2021 2022 - Sep 21 24:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Tehran 3:25:44 - LMT 1916
3:25:44 - TMT 1935 Jun 13 # Tehran Mean Time
3:30 Iran +0330/+0430 1977 Oct 20 24:00
4:00 Iran +04/+05 1979
3:30 Iran +0330/+0430
3:30 Iran %z 1977 Oct 20 24:00
4:00 Iran %z 1979
3:30 Iran %z
# Iraq
@@ -1687,8 +1694,8 @@ Rule Iraq 1991 2007 - Oct 1 3:00s 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Baghdad 2:57:40 - LMT 1890
2:57:36 - BMT 1918 # Baghdad Mean Time?
3:00 - +03 1982 May
3:00 Iraq +03/+04
3:00 - %z 1982 May
3:00 Iraq %z
###############################################################################
@@ -2285,7 +2292,7 @@ Rule Jordan 2022 only - Feb lastThu 24:00 1:00 S
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Amman 2:23:44 - LMT 1931
2:00 Jordan EE%sT 2022 Oct 28 0:00s
3:00 - +03
3:00 - %z
# Kazakhstan
@@ -2496,88 +2503,88 @@ Zone Asia/Amman 2:23:44 - LMT 1931
# Almaty (formerly Alma-Ata), representing most locations in Kazakhstan
# This includes Abai/Abay (ISO 3166-2 code KZ-10), Aqmola/Akmola (KZ-11),
# Almaty (KZ-19), Almaty city (KZ-75), Astana city (KZ-71),
# East Kazkhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33),
# East Kazakhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33),
# Karaganda (KZ-35), North Kazakhstan (KZ-59), Pavlodar (KZ-55),
# Shyumkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62).
# Shymkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62).
Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata
5:00 - +05 1930 Jun 21
6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s
5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s
6:00 RussiaAsia +06/+07 2004 Oct 31 2:00s
6:00 - +06 2024 Mar 1 0:00
5:00 - +05
5:00 - %z 1930 Jun 21
6:00 RussiaAsia %z 1991 Mar 31 2:00s
5:00 RussiaAsia %z 1992 Jan 19 2:00s
6:00 RussiaAsia %z 2004 Oct 31 2:00s
6:00 - %z 2024 Mar 1 0:00
5:00 - %z
# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-43)
Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2
4:00 - +04 1930 Jun 21
5:00 - +05 1981 Apr 1
5:00 1:00 +06 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
4:00 RussiaAsia +04/+05 1991 Sep 29 2:00s
5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s
6:00 RussiaAsia +06/+07 1992 Mar 29 2:00s
5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s
6:00 - +06 2018 Dec 21 0:00
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 - %z 1981 Apr 1
5:00 1:00 %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1991 Mar 31 2:00s
4:00 RussiaAsia %z 1991 Sep 29 2:00s
5:00 RussiaAsia %z 1992 Jan 19 2:00s
6:00 RussiaAsia %z 1992 Mar 29 2:00s
5:00 RussiaAsia %z 2004 Oct 31 2:00s
6:00 - %z 2018 Dec 21 0:00
5:00 - %z
# Qostanay (aka Kostanay, Kustanay) (KZ-39)
# The 1991/2 rules are unclear partly because of the 1997 Turgai
# reorganization.
Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2
4:00 - +04 1930 Jun 21
5:00 - +05 1981 Apr 1
5:00 1:00 +06 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s
6:00 - +06 2024 Mar 1 0:00
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 - %z 1981 Apr 1
5:00 1:00 %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1991 Mar 31 2:00s
4:00 RussiaAsia %z 1992 Jan 19 2:00s
5:00 RussiaAsia %z 2004 Oct 31 2:00s
6:00 - %z 2024 Mar 1 0:00
5:00 - %z
# Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-15)
Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2
4:00 - +04 1930 Jun 21
5:00 - +05 1981 Apr 1
5:00 1:00 +06 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 - %z 1981 Apr 1
5:00 1:00 %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1991 Mar 31 2:00s
4:00 RussiaAsia %z 1992 Jan 19 2:00s
5:00 RussiaAsia %z 2004 Oct 31 2:00s
5:00 - %z
# Mangghystaū (KZ-47)
# Aqtau was not founded until 1963, but it represents an inhabited region,
# so include timestamps before 1963.
Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2
4:00 - +04 1930 Jun 21
5:00 - +05 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
5:00 RussiaAsia +05/+06 1994 Sep 25 2:00s
4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 - %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1991 Mar 31 2:00s
4:00 RussiaAsia %z 1992 Jan 19 2:00s
5:00 RussiaAsia %z 1994 Sep 25 2:00s
4:00 RussiaAsia %z 2004 Oct 31 2:00s
5:00 - %z
# Atyraū (KZ-23) is like Mangghystaū except it switched from
# +04/+05 to +05/+06 in spring 1999, not fall 1994.
Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2
3:00 - +03 1930 Jun 21
5:00 - +05 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
5:00 RussiaAsia +05/+06 1999 Mar 28 2:00s
4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s
5:00 - +05
3:00 - %z 1930 Jun 21
5:00 - %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1991 Mar 31 2:00s
4:00 RussiaAsia %z 1992 Jan 19 2:00s
5:00 RussiaAsia %z 1999 Mar 28 2:00s
4:00 RussiaAsia %z 2004 Oct 31 2:00s
5:00 - %z
# West Kazakhstan (KZ-27)
# From Paul Eggert (2016-03-18):
# The 1989 transition is from USSR act No. 227 (1989-03-14).
Zone Asia/Oral 3:25:24 - LMT 1924 May 2 # or Ural'sk
3:00 - +03 1930 Jun 21
5:00 - +05 1981 Apr 1
5:00 1:00 +06 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1989 Mar 26 2:00s
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s
5:00 RussiaAsia +05/+06 1992 Mar 29 2:00s
4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s
5:00 - +05
3:00 - %z 1930 Jun 21
5:00 - %z 1981 Apr 1
5:00 1:00 %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1989 Mar 26 2:00s
4:00 RussiaAsia %z 1992 Jan 19 2:00s
5:00 RussiaAsia %z 1992 Mar 29 2:00s
4:00 RussiaAsia %z 2004 Oct 31 2:00s
5:00 - %z
# Kyrgyzstan (Kirgizstan)
# Transitions through 1991 are from Shanks & Pottenger.
@@ -2598,11 +2605,11 @@ Rule Kyrgyz 1997 2005 - Mar lastSun 2:30 1:00 -
Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2
5:00 - +05 1930 Jun 21
6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s
5:00 RussiaAsia +05/+06 1991 Aug 31 2:00
5:00 Kyrgyz +05/+06 2005 Aug 12
6:00 - +06
5:00 - %z 1930 Jun 21
6:00 RussiaAsia %z 1991 Mar 31 2:00s
5:00 RussiaAsia %z 1991 Aug 31 2:00
5:00 Kyrgyz %z 2005 Aug 12
6:00 - %z
###############################################################################
@@ -2809,16 +2816,16 @@ Rule NBorneo 1935 1941 - Dec 14 0:00 0 -
# and 1982 transition dates are from Mok Ly Yng.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Kuching 7:21:20 - LMT 1926 Mar
7:30 - +0730 1933
8:00 NBorneo +08/+0820 1942 Feb 16
9:00 - +09 1945 Sep 12
8:00 - +08
7:30 - %z 1933
8:00 NBorneo %z 1942 Feb 16
9:00 - %z 1945 Sep 12
8:00 - %z
# Maldives
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé
4:54:00 - MMT 1960 # Malé Mean Time
5:00 - +05
5:00 - %z
# Mongolia
@@ -2920,9 +2927,37 @@ Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé
# From Arthur David Olson (2008-05-19):
# Assume that Choibalsan is indeed offset by 8:00.
# XXX--in the absence of better information, assume that transition
# was at the start of 2008-03-31 (the day of Steffen Thorsen's report);
# this is almost surely wrong.
# From Heitor David Pinto (2024-06-23):
# Sources about time zones in Mongolia seem to list one of two conflicting
# configurations. The first configuration, mentioned in a comment to the TZ
# database in 1999, citing a Mongolian government website, lists the provinces
# of Bayan-Ölgii, Khovd and Uvs in UTC+7, and the rest of the country in
# UTC+8. The second configuration, mentioned in a comment to the database in
# 2001, lists Bayan-Ölgii, Khovd, Uvs, Govi-Altai and Zavkhan in UTC+7, Dornod
# and Sükhbaatar in UTC+9, and the rest of the country in UTC+8.
#
# The first configuration is still mentioned by several Mongolian travel
# agencies:
# https://www.adventurerider.mn/en/page/about_mongolia
# http://www.naturetours.mn/nt/mongolia.php
# https://www.newjuulchin.mn/web/content/7506?unique=fa24a0f6e96e022a3578ee5195ac879638c734ce
#
# It also matches these flight schedules in 2013:
# http://web.archive.org/web/20130722023600/https://www.hunnuair.com/en/timetabled
# The flight times imply that the airports of Uliastai (Zavkhan), Choibalsan
# (Dornod) and Altai (Govi-Altai) are in the same time zone as Ulaanbaatar,
# and Khovd is one hour behind....
#
# The second configuration was mentioned by an official of the Mongolian
# standards agency in an interview in 2014: https://ikon.mn/n/9v6
# And it's still listed by the Mongolian aviation agency:
# https://ais.mn/files/aip/eAIP/2023-12-25/html/eSUP/ZM-eSUP-23-04-en-MN.html
#
# ... I believe that the first configuration is what is actually observed in
# Mongolia and has been so all along, at least since 1999. The second
# configuration closely matches the ideal time zone boundaries at 97.5° E and
# 112.5° E but it doesn't seem to be used in practice.
# From Ganbold Tsagaankhuu (2015-03-10):
# It seems like yesterday Mongolian Government meeting has concluded to use
@@ -2961,25 +2996,18 @@ Rule Mongol 2015 2016 - Sep lastSat 0:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
# Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
Zone Asia/Hovd 6:06:36 - LMT 1905 Aug
6:00 - +06 1978
7:00 Mongol +07/+08
6:00 - %z 1978
7:00 Mongol %z
# Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga
Zone Asia/Ulaanbaatar 7:07:32 - LMT 1905 Aug
7:00 - +07 1978
8:00 Mongol +08/+09
# Choibalsan, a.k.a. Bajan Tümen, Bajan Tumen, Chojbalsan,
# Choybalsan, Sanbejse, Tchoibalsan
Zone Asia/Choibalsan 7:38:00 - LMT 1905 Aug
7:00 - +07 1978
8:00 - +08 1983 Apr
9:00 Mongol +09/+10 2008 Mar 31
8:00 Mongol +08/+09
7:00 - %z 1978
8:00 Mongol %z
# Nepal
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Kathmandu 5:41:16 - LMT 1920
5:30 - +0530 1986
5:45 - +0545
5:30 - %z 1986
5:45 - %z
# Pakistan
@@ -3125,10 +3153,10 @@ Rule Pakistan 2009 only - Apr 15 0:00 1:00 S
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Karachi 4:28:12 - LMT 1907
5:30 - +0530 1942 Sep
5:30 1:00 +0630 1945 Oct 15
5:30 - +0530 1951 Sep 30
5:00 - +05 1971 Mar 26
5:30 - %z 1942 Sep
5:30 1:00 %z 1945 Oct 15
5:30 - %z 1951 Sep 30
5:00 - %z 1971 Mar 26
5:00 Pakistan PK%sT # Pakistan Time
# Palestine
@@ -3676,14 +3704,14 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct
# Philippine Star 2014-08-05
# http://www.philstar.com/headlines/2014/08/05/1354152/pnoy-urged-declare-use-daylight-saving-time
# From Paul Goyette (2018-06-15):
# From Paul Goyette (2018-06-15) with URLs updated by Guy Harris (2024-02-15):
# In the Philippines, there is a national law, Republic Act No. 10535
# which declares the official time here as "Philippine Standard Time".
# The act [1] even specifies use of PST as the abbreviation, although
# the FAQ provided by PAGASA [2] uses the "acronym PhST to distinguish
# it from the Pacific Standard Time (PST)."
# [1] http://www.officialgazette.gov.ph/2013/05/15/republic-act-no-10535/
# [2] https://www1.pagasa.dost.gov.ph/index.php/astronomy/philippine-standard-time#republic-act-10535
# [1] https://www.officialgazette.gov.ph/2013/05/15/republic-act-no-10535/
# [2] https://prsd.pagasa.dost.gov.ph/index.php/28-astronomy/302-philippine-standard-time
#
# From Paul Eggert (2018-06-19):
# I surveyed recent news reports, and my impression is that "PST" is
@@ -3716,8 +3744,8 @@ Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31
# Qatar
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha
4:00 - +04 1972 Jun
3:00 - +03
4:00 - %z 1972 Jun
3:00 - %z
# Kuwait
# Saudi Arabia
@@ -3767,7 +3795,7 @@ Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14
3:00 - +03
3:00 - %z
# Singapore
# taken from Mok Ly Yng (2003-10-30)
@@ -3775,13 +3803,13 @@ Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1
6:55:25 - SMT 1905 Jun 1 # Singapore M.T.
7:00 - +07 1933 Jan 1
7:00 0:20 +0720 1936 Jan 1
7:20 - +0720 1941 Sep 1
7:30 - +0730 1942 Feb 16
9:00 - +09 1945 Sep 12
7:30 - +0730 1981 Dec 31 16:00u
8:00 - +08
7:00 - %z 1933 Jan 1
7:00 0:20 %z 1936 Jan 1
7:20 - %z 1941 Sep 1
7:30 - %z 1942 Feb 16
9:00 - %z 1945 Sep 12
7:30 - %z 1981 Dec 31 16:00u
8:00 - %z
# Spratly Is
# no information
@@ -3839,13 +3867,13 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Colombo 5:19:24 - LMT 1880
5:19:32 - MMT 1906 # Moratuwa Mean Time
5:30 - +0530 1942 Jan 5
5:30 0:30 +06 1942 Sep
5:30 1:00 +0630 1945 Oct 16 2:00
5:30 - +0530 1996 May 25 0:00
6:30 - +0630 1996 Oct 26 0:30
6:00 - +06 2006 Apr 15 0:30
5:30 - +0530
5:30 - %z 1942 Jan 5
5:30 0:30 %z 1942 Sep
5:30 1:00 %z 1945 Oct 16 2:00
5:30 - %z 1996 May 25 0:00
6:30 - %z 1996 Oct 26 0:30
6:00 - %z 2006 Apr 15 0:30
5:30 - %z
# Syria
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
@@ -4016,16 +4044,16 @@ Rule Syria 2009 2022 - Oct lastFri 0:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq
2:00 Syria EE%sT 2022 Oct 28 0:00
3:00 - +03
3:00 - %z
# Tajikistan
# From Shanks & Pottenger.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2
5:00 - +05 1930 Jun 21
6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s
5:00 1:00 +06 1991 Sep 9 2:00s
5:00 - +05
5:00 - %z 1930 Jun 21
6:00 RussiaAsia %z 1991 Mar 31 2:00s
5:00 1:00 %z 1991 Sep 9 2:00s
5:00 - %z
# Cambodia
# Christmas I
@@ -4035,16 +4063,16 @@ Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Bangkok 6:42:04 - LMT 1880
6:42:04 - BMT 1920 Apr # Bangkok Mean Time
7:00 - +07
7:00 - %z
# Turkmenistan
# From Shanks & Pottenger.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad
4:00 - +04 1930 Jun 21
5:00 RussiaAsia +05/+06 1991 Mar 31 2:00
4:00 RussiaAsia +04/+05 1992 Jan 19 2:00
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 RussiaAsia %z 1991 Mar 31 2:00
4:00 RussiaAsia %z 1992 Jan 19 2:00
5:00 - %z
# Oman
# Réunion
@@ -4054,25 +4082,25 @@ Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad
# The Crozet Is also observe Réunion time; see the 'antarctica' file.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Dubai 3:41:12 - LMT 1920
4:00 - +04
4:00 - %z
# Uzbekistan
# Byalokoz 1919 says Uzbekistan was 4:27:53.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Samarkand 4:27:53 - LMT 1924 May 2
4:00 - +04 1930 Jun 21
5:00 - +05 1981 Apr 1
5:00 1:00 +06 1981 Oct 1
6:00 - +06 1982 Apr 1
5:00 RussiaAsia +05/+06 1992
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 - %z 1981 Apr 1
5:00 1:00 %z 1981 Oct 1
6:00 - %z 1982 Apr 1
5:00 RussiaAsia %z 1992
5:00 - %z
# Milne says Tashkent was 4:37:10.8.
#STDOFF 4:37:10.8
Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2
5:00 - +05 1930 Jun 21
6:00 RussiaAsia +06/+07 1991 Mar 31 2:00
5:00 RussiaAsia +05/+06 1992
5:00 - +05
5:00 - %z 1930 Jun 21
6:00 RussiaAsia %z 1991 Mar 31 2:00
5:00 RussiaAsia %z 1992
5:00 - %z
# Vietnam (southern)
@@ -4130,7 +4158,7 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2
# Võ Nguyên Giáp, Việt Nam Dân Quốc Công Báo, No. 1 (1945-09-29), page 13
# http://baochi.nlv.gov.vn/baochi/cgi-bin/baochi?a=d&d=JwvzO19450929.2.5&dliv=none
# It says that on 1945-09-01 at 24:00, Vietnam moved back two hours, to +07.
# It also mentions a 1945-03-29 decree (by a Japanese Goveror-General)
# It also mentions a 1945-03-29 decree (by a Japanese Governor-General)
# to set the time zone to +09, but does not say whether that decree
# merely legalized an earlier change to +09.
#
@@ -4151,14 +4179,14 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2
#STDOFF 7:06:30.13
Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1
7:06:30 - PLMT 1911 May 1 # Phù Liễn MT
7:00 - +07 1942 Dec 31 23:00
8:00 - +08 1945 Mar 14 23:00
9:00 - +09 1945 Sep 1 24:00
7:00 - +07 1947 Apr 1
8:00 - +08 1955 Jul 1 01:00
7:00 - +07 1959 Dec 31 23:00
8:00 - +08 1975 Jun 13
7:00 - +07
7:00 - %z 1942 Dec 31 23:00
8:00 - %z 1945 Mar 14 23:00
9:00 - %z 1945 Sep 1 24:00
7:00 - %z 1947 Apr 1
8:00 - %z 1955 Jul 1 01:00
7:00 - %z 1959 Dec 31 23:00
8:00 - %z 1975 Jun 13
7:00 - %z
# From Paul Eggert (2019-02-19):
#

View File

@@ -66,8 +66,8 @@ Zone Australia/Perth 7:43:24 - LMT 1895 Dec
8:00 Aus AW%sT 1943 Jul
8:00 AW AW%sT
Zone Australia/Eucla 8:35:28 - LMT 1895 Dec
8:45 Aus +0845/+0945 1943 Jul
8:45 AW +0845/+0945
8:45 Aus %z 1943 Jul
8:45 AW %z
# Queensland
#
@@ -232,8 +232,8 @@ Rule LH 2008 max - Apr Sun>=1 2:00 0 -
Rule LH 2008 max - Oct Sun>=1 2:00 0:30 -
Zone Australia/Lord_Howe 10:36:20 - LMT 1895 Feb
10:00 - AEST 1981 Mar
10:30 LH +1030/+1130 1985 Jul
10:30 LH +1030/+11
10:30 LH %z 1985 Jul
10:30 LH %z
# Australian miscellany
#
@@ -439,16 +439,16 @@ Rule Fiji 2019 only - Nov Sun>=8 2:00 1:00 -
Rule Fiji 2020 only - Dec 20 2:00 1:00 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva
12:00 Fiji +12/+13
12:00 Fiji %z
# French Polynesia
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct 1 # Rikitea
-9:00 - -09
-9:00 - %z
Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct 1
-9:30 - -0930
-9:30 - %z
Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct 1 # Papeete
-10:00 - -10
-10:00 - %z
# Clipperton (near North America) is administered from French Polynesia;
# it is uninhabited.
@@ -491,7 +491,7 @@ Rule Guam 1977 only - Aug 28 2:00 0 S
Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31
9:39:00 - LMT 1901 # Agana
10:00 - GST 1941 Dec 10 # Guam
9:00 - +09 1944 Jul 31
9:00 - %z 1944 Jul 31
10:00 Guam G%sT 2000 Dec 23
10:00 - ChST # Chamorro Standard Time
@@ -503,30 +503,30 @@ Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31
# Wallis & Futuna
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Tarawa 11:32:04 - LMT 1901 # Bairiki
12:00 - +12
12:00 - %z
# Kiribati (except Gilbert Is)
# See Pacific/Tarawa for the Gilbert Is.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Kanton 0 - -00 1937 Aug 31
-12:00 - -12 1979 Oct
-11:00 - -11 1994 Dec 31
13:00 - +13
-12:00 - %z 1979 Oct
-11:00 - %z 1994 Dec 31
13:00 - %z
Zone Pacific/Kiritimati -10:29:20 - LMT 1901
-10:40 - -1040 1979 Oct
-10:00 - -10 1994 Dec 31
14:00 - +14
-10:40 - %z 1979 Oct
-10:00 - %z 1994 Dec 31
14:00 - %z
# Marshall Is
# See Pacific/Tarawa for most locations.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Kwajalein 11:09:20 - LMT 1901
11:00 - +11 1937
10:00 - +10 1941 Apr 1
9:00 - +09 1944 Feb 6
11:00 - +11 1969 Oct
-12:00 - -12 1993 Aug 20 24:00
12:00 - +12
11:00 - %z 1937
10:00 - %z 1941 Apr 1
9:00 - %z 1944 Feb 6
11:00 - %z 1969 Oct
-12:00 - %z 1993 Aug 20 24:00
12:00 - %z
# Micronesia
# For Chuuk and Yap see Pacific/Port_Moresby.
@@ -534,22 +534,22 @@ Zone Pacific/Kwajalein 11:09:20 - LMT 1901
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Kosrae -13:08:04 - LMT 1844 Dec 31
10:51:56 - LMT 1901
11:00 - +11 1914 Oct
9:00 - +09 1919 Feb 1
11:00 - +11 1937
10:00 - +10 1941 Apr 1
9:00 - +09 1945 Aug
11:00 - +11 1969 Oct
12:00 - +12 1999
11:00 - +11
11:00 - %z 1914 Oct
9:00 - %z 1919 Feb 1
11:00 - %z 1937
10:00 - %z 1941 Apr 1
9:00 - %z 1945 Aug
11:00 - %z 1969 Oct
12:00 - %z 1999
11:00 - %z
# Nauru
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Nauru 11:07:40 - LMT 1921 Jan 15 # Uaobe
11:30 - +1130 1942 Aug 29
9:00 - +09 1945 Sep 8
11:30 - +1130 1979 Feb 10 2:00
12:00 - +12
11:30 - %z 1942 Aug 29
9:00 - %z 1945 Sep 8
11:30 - %z 1979 Feb 10 2:00
12:00 - %z
# New Caledonia
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
@@ -560,7 +560,7 @@ Rule NC 1996 only - Dec 1 2:00s 1:00 -
Rule NC 1997 only - Mar 2 2:00s 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Noumea 11:05:48 - LMT 1912 Jan 13 # Nouméa
11:00 NC +11/+12
11:00 NC %z
###############################################################################
@@ -604,8 +604,8 @@ Zone Pacific/Auckland 11:39:04 - LMT 1868 Nov 2
12:00 NZ NZ%sT
Zone Pacific/Chatham 12:13:48 - LMT 1868 Nov 2
12:15 - +1215 1946 Jan 1
12:45 Chatham +1245/+1345
12:15 - %z 1946 Jan 1
12:45 Chatham %z
# Auckland Is
# uninhabited; Māori and Moriori, colonial settlers, pastoralists, sealers,
@@ -658,8 +658,8 @@ Rule Cook 1979 1990 - Oct lastSun 0:00 0:30 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua
-10:39:04 - LMT 1952 Oct 16
-10:30 - -1030 1978 Nov 12
-10:00 Cook -10/-0930
-10:30 - %z 1978 Nov 12
-10:00 Cook %z
###############################################################################
@@ -676,30 +676,30 @@ Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Niue -11:19:40 - LMT 1952 Oct 16 # Alofi
-11:20 - -1120 1964 Jul
-11:00 - -11
-11:20 - %z 1964 Jul
-11:00 - %z
# Norfolk
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Norfolk 11:11:52 - LMT 1901 # Kingston
11:12 - +1112 1951
11:30 - +1130 1974 Oct 27 02:00s
11:30 1:00 +1230 1975 Mar 2 02:00s
11:30 - +1130 2015 Oct 4 02:00s
11:00 - +11 2019 Jul
11:00 AN +11/+12
11:12 - %z 1951
11:30 - %z 1974 Oct 27 02:00s
11:30 1:00 %z 1975 Mar 2 02:00s
11:30 - %z 2015 Oct 4 02:00s
11:00 - %z 2019 Jul
11:00 AN %z
# Palau (Belau)
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Palau -15:02:04 - LMT 1844 Dec 31 # Koror
8:57:56 - LMT 1901
9:00 - +09
9:00 - %z
# Papua New Guinea
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Port_Moresby 9:48:40 - LMT 1880
9:48:32 - PMMT 1895 # Port Moresby Mean Time
10:00 - +10
10:00 - %z
#
# From Paul Eggert (2014-10-13):
# Base the Bougainville entry on the Arawa-Kieta region, which appears to have
@@ -720,16 +720,16 @@ Zone Pacific/Port_Moresby 9:48:40 - LMT 1880
#
Zone Pacific/Bougainville 10:22:16 - LMT 1880
9:48:32 - PMMT 1895
10:00 - +10 1942 Jul
9:00 - +09 1945 Aug 21
10:00 - +10 2014 Dec 28 2:00
11:00 - +11
10:00 - %z 1942 Jul
9:00 - %z 1945 Aug 21
10:00 - %z 2014 Dec 28 2:00
11:00 - %z
# Pitcairn
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Pitcairn -8:40:20 - LMT 1901 # Adamstown
-8:30 - -0830 1998 Apr 27 0:00
-8:00 - -08
-8:30 - %z 1998 Apr 27 0:00
-8:00 - %z
# American Samoa
# Midway
@@ -818,15 +818,15 @@ Rule WS 2012 2020 - Sep lastSun 3:00 1 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5
-11:26:56 - LMT 1911
-11:30 - -1130 1950
-11:00 WS -11/-10 2011 Dec 29 24:00
13:00 WS +13/+14
-11:30 - %z 1950
-11:00 WS %z 2011 Dec 29 24:00
13:00 WS %z
# Solomon Is
# excludes Bougainville, for which see Papua New Guinea
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara
11:00 - +11
11:00 - %z
# Tokelau
#
@@ -849,8 +849,8 @@ Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Fakaofo -11:24:56 - LMT 1901
-11:00 - -11 2011 Dec 30
13:00 - +13
-11:00 - %z 2011 Dec 30
13:00 - %z
# Tonga
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
@@ -862,9 +862,9 @@ Rule Tonga 2016 only - Nov Sun>=1 2:00 1:00 -
Rule Tonga 2017 only - Jan Sun>=15 3:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10
12:20 - +1220 1961
13:00 - +13 1999
13:00 Tonga +13/+14
12:20 - %z 1961
13:00 - %z 1999
13:00 Tonga %z
# US minor outlying islands
@@ -953,7 +953,7 @@ Rule Vanuatu 1992 1993 - Jan Sat>=22 24:00 0 -
Rule Vanuatu 1992 only - Oct Sat>=22 24:00 1:00 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila
11:00 Vanuatu +11/+12
11:00 Vanuatu %z
###############################################################################

View File

@@ -21,12 +21,13 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# tzdb links for backward compatibility
# Links and zones for backward compatibility
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.
# This file provides links from old or merged timezone names to current ones.
# It also provides a few zone entries for old naming conventions.
# Many names changed in 1993 and in 1995, and many merged names moved here
# in the period from 2013 through 2022. Several of these names are
# also present in the file 'backzone', which has data important only
@@ -67,6 +68,8 @@ Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre
Link America/Noronha Brazil/DeNoronha
Link America/Sao_Paulo Brazil/East
Link America/Manaus Brazil/West
Link Europe/Brussels CET
Link America/Chicago CST6CDT
Link America/Halifax Canada/Atlantic
Link America/Winnipeg Canada/Central
# This line is commented out, as the name exceeded the 14-character limit
@@ -81,6 +84,9 @@ Link America/Whitehorse Canada/Yukon
Link America/Santiago Chile/Continental
Link Pacific/Easter Chile/EasterIsland
Link America/Havana Cuba
Link Europe/Athens EET
Link America/Panama EST
Link America/New_York EST5EDT
Link Africa/Cairo Egypt
Link Europe/Dublin Eire
# Vanguard section, for most .zi parsers.
@@ -119,6 +125,9 @@ Link America/Jamaica Jamaica
Link Asia/Tokyo Japan
Link Pacific/Kwajalein Kwajalein
Link Africa/Tripoli Libya
Link Europe/Brussels MET
Link America/Phoenix MST
Link America/Denver MST7MDT
Link America/Tijuana Mexico/BajaNorte
Link America/Mazatlan Mexico/BajaSur
Link America/Mexico_City Mexico/General
@@ -298,6 +307,7 @@ Link America/Denver America/Shiprock
Link America/Toronto America/Thunder_Bay
Link America/Edmonton America/Yellowknife
Link Pacific/Auckland Antarctica/South_Pole
Link Asia/Ulaanbaatar Asia/Choibalsan
Link Asia/Shanghai Asia/Chongqing
Link Asia/Shanghai Asia/Harbin
Link Asia/Urumqi Asia/Kashgar
@@ -312,6 +322,7 @@ Link Europe/Kyiv Europe/Zaporozhye
Link Pacific/Kanton Pacific/Enderbury
Link Pacific/Honolulu Pacific/Johnston
Link Pacific/Port_Moresby Pacific/Yap
Link Europe/Lisbon WET
# Alternate names for the same location
@@ -337,5 +348,7 @@ Link Europe/Kyiv Europe/Kiev
# Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72.
# However, for various reasons many users expect to find it under Europe.
Link Asia/Nicosia Europe/Nicosia
Link Pacific/Honolulu HST
Link America/Los_Angeles PST8PDT
Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei
Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk

View File

@@ -28,7 +28,7 @@
# These entries are for uses not otherwise covered by the tz database.
# Their main practical use is for platforms like Android that lack
# support for POSIX.1-2017-style TZ strings. On such platforms these entries
# support for POSIX proleptic TZ strings. On such platforms these entries
# can be useful if the timezone database is wrong or if a ship or
# aircraft at sea is not in a timezone.
@@ -74,29 +74,29 @@ Link Etc/GMT GMT
# so we moved the names into the Etc subdirectory.
# Also, the time zone abbreviations are now compatible with %z.
Zone Etc/GMT-14 14 - +14
Zone Etc/GMT-13 13 - +13
Zone Etc/GMT-12 12 - +12
Zone Etc/GMT-11 11 - +11
Zone Etc/GMT-10 10 - +10
Zone Etc/GMT-9 9 - +09
Zone Etc/GMT-8 8 - +08
Zone Etc/GMT-7 7 - +07
Zone Etc/GMT-6 6 - +06
Zone Etc/GMT-5 5 - +05
Zone Etc/GMT-4 4 - +04
Zone Etc/GMT-3 3 - +03
Zone Etc/GMT-2 2 - +02
Zone Etc/GMT-1 1 - +01
Zone Etc/GMT+1 -1 - -01
Zone Etc/GMT+2 -2 - -02
Zone Etc/GMT+3 -3 - -03
Zone Etc/GMT+4 -4 - -04
Zone Etc/GMT+5 -5 - -05
Zone Etc/GMT+6 -6 - -06
Zone Etc/GMT+7 -7 - -07
Zone Etc/GMT+8 -8 - -08
Zone Etc/GMT+9 -9 - -09
Zone Etc/GMT+10 -10 - -10
Zone Etc/GMT+11 -11 - -11
Zone Etc/GMT+12 -12 - -12
Zone Etc/GMT-14 14 - %z
Zone Etc/GMT-13 13 - %z
Zone Etc/GMT-12 12 - %z
Zone Etc/GMT-11 11 - %z
Zone Etc/GMT-10 10 - %z
Zone Etc/GMT-9 9 - %z
Zone Etc/GMT-8 8 - %z
Zone Etc/GMT-7 7 - %z
Zone Etc/GMT-6 6 - %z
Zone Etc/GMT-5 5 - %z
Zone Etc/GMT-4 4 - %z
Zone Etc/GMT-3 3 - %z
Zone Etc/GMT-2 2 - %z
Zone Etc/GMT-1 1 - %z
Zone Etc/GMT+1 -1 - %z
Zone Etc/GMT+2 -2 - %z
Zone Etc/GMT+3 -3 - %z
Zone Etc/GMT+4 -4 - %z
Zone Etc/GMT+5 -5 - %z
Zone Etc/GMT+6 -6 - %z
Zone Etc/GMT+7 -7 - %z
Zone Etc/GMT+8 -8 - %z
Zone Etc/GMT+9 -9 - %z
Zone Etc/GMT+10 -10 - %z
Zone Etc/GMT+11 -11 - %z
Zone Etc/GMT+12 -12 - %z

View File

@@ -753,14 +753,6 @@ Rule Russia 1996 2010 - Oct lastSun 2:00s 0 -
# Take "abolishing daylight saving time" to mean that time is now considered
# to be standard.
# These are for backward compatibility with older versions.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone WET 0:00 EU WE%sT
Zone CET 1:00 C-Eur CE%sT
Zone MET 1:00 C-Eur ME%sT
Zone EET 2:00 EU EE%sT
# Previous editions of this database used abbreviations like MET DST
# for Central European Summer Time, but this didn't agree with common usage.
@@ -894,7 +886,7 @@ Zone Europe/Minsk 1:50:16 - LMT 1880
3:00 Russia MSK/MSD 1990
3:00 - MSK 1991 Mar 31 2:00s
2:00 Russia EE%sT 2011 Mar 27 2:00s
3:00 - +03
3:00 - %z
# Belgium
# Luxembourg
@@ -1199,22 +1191,22 @@ Rule Thule 2007 max - Nov Sun>=1 2:00 0 S
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28
-3:00 - -03 1980 Apr 6 2:00
-3:00 EU -03/-02 1996
-3:00 - %z 1980 Apr 6 2:00
-3:00 EU %z 1996
0:00 - GMT
#
# Use the old name Scoresbysund, as the current name Ittoqqortoormiit
# exceeds tzdb's 14-letter limit and has no common English abbreviation.
Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit
-2:00 - -02 1980 Apr 6 2:00
-2:00 C-Eur -02/-01 1981 Mar 29
-1:00 EU -01/+00 2024 Mar 31
-2:00 EU -02/-01
-2:00 - %z 1980 Apr 6 2:00
-2:00 C-Eur %z 1981 Mar 29
-1:00 EU %z 2024 Mar 31
-2:00 EU %z
Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb
-3:00 - -03 1980 Apr 6 2:00
-3:00 EU -03/-02 2023 Mar 26 1:00u
-2:00 - -02 2023 Oct 29 1:00u
-2:00 EU -02/-01
-3:00 - %z 1980 Apr 6 2:00
-3:00 EU %z 2023 Mar 26 1:00u
-2:00 - %z 2023 Oct 29 1:00u
-2:00 EU %z
Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik
-4:00 Thule A%sT
@@ -2086,10 +2078,39 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880
# Portugal
# From Paul Eggert (2014-08-11), after a heads-up from Stephen Colebourne:
# According to a Portuguese decree (1911-05-26)
# https://dre.pt/application/dir/pdf1sdip/1911/05/12500/23132313.pdf
# Lisbon was at -0:36:44.68, but switched to GMT on 1912-01-01 at 00:00.
# From Tim Parenti (2024-07-01), per Alois Treindl (2021-02-07) and Michael
# Deckers (2021-02-10):
# http://oal.ul.pt/documentos/2018/01/hl1911a2018.pdf/
# The Astronomical Observatory of Lisbon has published a list detailing the
# historical transitions in legal time within continental Portugal. It
# directly references many decrees and ordinances which are, in turn,
# referenced below. They can be viewed in the public archives of the Diário da
# República (until 1976-04-09 known as the Diário do Govêrno) at
# https://dre.pt/ (in Portuguese).
#
# Most of the Rules below have been updated simply to match the Observatory's
# listing for continental (mainland) Portugal. Although there are over 50
# referenced decrees and ordinances, only the handful with comments below have
# been verified against the text, typically to provide additional confidence
# wherever dates provided by Whitman and Shanks & Pottenger had disagreed.
# See further below for the Azores and Madeira.
# From Tim Parenti (2024-07-01), per Paul Eggert (2014-08-11), after a
# heads-up from Stephen Colebourne:
# According to a 1911-05-24 Portuguese decree, Lisbon was at -0:36:44.68, but
# switched to GMT on 1912-01-01 at 00:00.
# https://dre.pt/dr/detalhe/decreto/593090
# https://dre.pt/application/conteudo/593090
# The decree made legal time throughout Portugal and her possessions
# "subordinate to the Greenwich meridian, according to the principle adopted at
# the Washington Convention in 1884" and eliminated the "difference of five
# minutes between the internal and external clocks of railway stations".
#
# The decree was gazetted in the 1911-05-30 issue of Diário do Govêrno, and is
# considered to be dated 1911-05-24 by that issue's summary; however, the text
# of the decree itself is dated 1911-05-26. The Diário da República website
# notes the discrepancy, but later laws and the Observatory all seem to refer
# to this decree by the 1911-05-24 date.
#
# From Michael Deckers (2018-02-15):
# article 5 [of the 1911 decree; Deckers's translation] ...:
@@ -2097,37 +2118,62 @@ Zone Europe/Warsaw 1:24:00 - LMT 1880
# according to the 2nd article, the civil day January 1, 1912 begins,
# all clocks therefore having to be advanced or set back correspondingly ...
# From Rui Pedro Salgueiro (1992-11-12):
# Portugal has recently (September, 27) changed timezone
# (from WET to MET or CET) to harmonize with EEC.
#
# Martin Bruckmann (1996-02-29) reports via Peter Ilieve
# that Portugal is reverting to 0:00 by not moving its clocks this spring.
# The new Prime Minister was fed up with getting up in the dark in the winter.
#
# From Paul Eggert (1996-11-12):
# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions
# at 02:00u, not 01:00u. Assume that these are typos.
# IATA SSIM (1991/1992) reports that the Azores were at -1:00.
# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00.
# Guess that the Azores changed to EU rules in 1992 (since that's when Portugal
# harmonized with EU rules), and that they stayed +0:00 that winter.
#
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not
# done every year, depending on what Spain did, because of railroad schedules.
# Go with Shanks & Pottenger.
# From Tim Parenti (2024-07-01), per Paul Eggert (1999-01-30):
# DSH writes in their history that Decreto 1469 of 1915-03-30 established
# summer time and that, "despite" this, the change to the clocks was not done
# every year, depending on what Spain did, because of railroad schedules.
# In fact, that decree had nothing to do with DST; rather, it regulated the
# sending of time signals. But we do see linkage to Spain in the 1920s below.
# https://dre.pt/dr/detalhe/decreto/1469-1915-285721
# https://dre.pt/application/conteudo/285721
#
# According to the Observatory, standard time was first advanced by Decreto
# 2433 of 1916-06-09 and restored by Decreto 2712 of 1916-10-28. While Whitman
# gives 1916-10-31 for the latter transition, Shanks & Pottenger agrees more
# closely with the decree, which stated that its provision "will start sixty
# minutes after the end of 31 October, according to the current time," i.e.,
# 01:00 on 1 November.
# https://dre.pt/dr/detalhe/decreto/2433-1916-267192
# https://dre.pt/application/conteudo/267192
# https://dre.pt/dr/detalhe/decreto/2712-1916-590937
# https://dre.pt/application/conteudo/590937
Rule Port 1916 only - Jun 17 23:00 1:00 S
# Whitman gives 1916 Oct 31; go with Shanks & Pottenger.
Rule Port 1916 only - Nov 1 1:00 0 -
Rule Port 1917 only - Feb 28 23:00s 1:00 S
Rule Port 1917 1921 - Oct 14 23:00s 0 -
Rule Port 1918 only - Mar 1 23:00s 1:00 S
Rule Port 1919 only - Feb 28 23:00s 1:00 S
Rule Port 1920 only - Feb 29 23:00s 1:00 S
Rule Port 1921 only - Feb 28 23:00s 1:00 S
# From Tim Parenti (2024-07-01):
# Article 7 of Decreto 2922 of 1916-12-30 stated that "the legal time will be
# advanced by sixty minutes from 1 March to 31 October." Per Article 15, this
# came into force from 1917-01-01. Just before the first fall back, Decreto
# 3446 of 1917-10-11 changed the annual end date to 14 October.
# https://dre.pt/dr/detalhe/decreto/2922-1916-261894
# https://dre.pt/application/conteudo/261894
# https://dre.pt/dr/detalhe/decreto/3446-1917-495161
# https://dre.pt/application/conteudo/495161
# This annual change was revoked by Decreto 8038 of 1922-02-18.
# https://dre.pt/dr/detalhe/decreto/8038-1922-569751
# https://dre.pt/application/conteudo/569751
Rule Port 1917 1921 - Mar 1 0:00 1:00 S
Rule Port 1917 1921 - Oct 14 24:00 0 -
# From Tim Parenti (2024-07-01):
# Decreto 9592 of 1924-04-14 noted that "France maintains the advance of legal
# time in the summer and Spain has now adopted it for the first time" and
# considered "that the absence of similar measures would cause serious
# difficulties for international rail connections with consequent repercussions
# on domestic service hours..." along with "inconvenient analogues...for postal
# and telegraph services." Summer time would be in effect from 17 April to 4
# October, with the spring change explicitly specified by bringing clocks
# forward from 16 April 23:00.
# https://dre.pt/dr/detalhe/decreto/9592-1924-652133
# https://dre.pt/application/conteudo/652133
#
# Decreto 10700, issued 1925-04-16, noted that Spain had not continued summer
# time, declared that "the current legal hour prior to 17 April remains
# unchanged from that day forward", and revoked legislation to the contrary,
# just a day before summer time would have otherwise resumed.
# https://dre.pt/dr/detalhe/decreto/10700-1925-437826
# https://dre.pt/application/conteudo/437826
Rule Port 1924 only - Apr 16 23:00s 1:00 S
Rule Port 1924 only - Oct 14 23:00s 0 -
Rule Port 1924 only - Oct 4 23:00s 0 -
Rule Port 1926 only - Apr 17 23:00s 1:00 S
Rule Port 1926 1929 - Oct Sat>=1 23:00s 0 -
Rule Port 1927 only - Apr 9 23:00s 1:00 S
@@ -2139,6 +2185,8 @@ Rule Port 1931 1932 - Oct Sat>=1 23:00s 0 -
Rule Port 1932 only - Apr 2 23:00s 1:00 S
Rule Port 1934 only - Apr 7 23:00s 1:00 S
# Whitman gives 1934 Oct 5; go with Shanks & Pottenger.
# Note: The 1935 law specified 10-06 00:00, not 10-05 24:00, but the following
# is equivalent and more succinct.
Rule Port 1934 1938 - Oct Sat>=1 23:00s 0 -
# Shanks & Pottenger give 1935 Apr 30; go with Whitman.
Rule Port 1935 only - Mar 30 23:00s 1:00 S
@@ -2149,10 +2197,19 @@ Rule Port 1938 only - Mar 26 23:00s 1:00 S
Rule Port 1939 only - Apr 15 23:00s 1:00 S
# Whitman gives 1939 Oct 7; go with Shanks & Pottenger.
Rule Port 1939 only - Nov 18 23:00s 0 -
# From Tim Parenti (2024-07-01):
# Portaria 9465 of 1940-02-17 advanced clocks from Saturday 1940-02-24 23:00.
# The clocks were restored by Portaria 9658, issued Monday 1940-10-07,
# effective from 24:00 that very night, which agrees with Shanks & Pottenger;
# Whitman gives Saturday 1940-10-05 instead.
# https://dre.pt/dr/detalhe/portaria/9465-1940-189096
# https://dre.pt/application/conteudo/189096
# https://dre.pt/dr/detalhe/portaria/9658-1940-196729
# https://dre.pt/application/conteudo/196729
Rule Port 1940 only - Feb 24 23:00s 1:00 S
# Shanks & Pottenger give 1940 Oct 7; go with Whitman.
Rule Port 1940 1941 - Oct 5 23:00s 0 -
Rule Port 1940 only - Oct 7 23:00s 0 -
Rule Port 1941 only - Apr 5 23:00s 1:00 S
Rule Port 1941 only - Oct 5 23:00s 0 -
Rule Port 1942 1945 - Mar Sat>=8 23:00s 1:00 S
Rule Port 1942 only - Apr 25 22:00s 2:00 M # Midsummer
Rule Port 1942 only - Aug 15 22:00s 1:00 S
@@ -2162,66 +2219,195 @@ Rule Port 1943 1945 - Aug Sat>=25 22:00s 1:00 S
Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 M
Rule Port 1946 only - Apr Sat>=1 23:00s 1:00 S
Rule Port 1946 only - Oct Sat>=1 23:00s 0 -
# Whitman says DST was not observed in 1950; go with Shanks & Pottenger.
# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger.
Rule Port 1947 1965 - Apr Sun>=1 2:00s 1:00 S
# From Tim Parenti (2024-07-01), per Alois Treindl (2021-02-07):
# The Astronomical Observatory of Lisbon cites Portaria 11767 of 1947-03-28 for
# 1947 and Portaria 12286 of 1948-02-19 for 1948.
# https://dre.pt/dr/detalhe/portaria/11767-1947-414787
# https://dre.pt/application/conteudo/414787
# https://dre.pt/dr/detalhe/portaria/12286-1948-152953
# https://dre.pt/application/conteudo/152953
#
# Although the latter ordinance explicitly had the 1948-10-03 transition
# scheduled for 02:00 rather than 03:00 as had been used in 1947, Decreto-Lei
# 37048 of 1948-09-07 recognized "that it is advisable to definitely set...the
# 'summer time' regime", and fixed the fall transition at 03:00 moving forward.
# https://dre.pt/dr/detalhe/decreto-lei/37048-1948-373810
# https://dre.pt/application/conteudo/373810
# While the Observatory only cites this act for 1949-1965 and not for 1948, it
# does not appear to have had any provision delaying its effect, so assume that
# it overrode the prior ordinance for 1948-10-03.
#
# Whitman says DST was not observed in 1950 and gives Oct lastSun for 1952 on.
# The Observatory, however, agrees with Shanks & Pottenger that 1950 was not an
# exception and that Oct Sun>=1 was maintained through 1965.
Rule Port 1947 1966 - Apr Sun>=1 2:00s 1:00 S
Rule Port 1947 1965 - Oct Sun>=1 2:00s 0 -
Rule Port 1977 only - Mar 27 0:00s 1:00 S
Rule Port 1977 only - Sep 25 0:00s 0 -
Rule Port 1978 1979 - Apr Sun>=1 0:00s 1:00 S
Rule Port 1978 only - Oct 1 0:00s 0 -
Rule Port 1979 1982 - Sep lastSun 1:00s 0 -
Rule Port 1980 only - Mar lastSun 0:00s 1:00 S
Rule Port 1981 1982 - Mar lastSun 1:00s 1:00 S
Rule Port 1983 only - Mar lastSun 2:00s 1:00 S
# From Tim Parenti (2024-07-01):
# Decreto-Lei 47233 of 1966-10-01 considered that the "duality" in time was
# "the cause of serious disturbances" and noted that "the countries with which
# we have the most frequent contacts...have already adopted" a solution
# coinciding with the extant "summer time". It established that the former
# "summer time" would apply year-round on the mainland and adjacent islands
# with immediate effect, as the fall back would have otherwise occurred later
# that evening.
# https://dre.pt/dr/detalhe/decreto-lei/47233-1966-293729
# Model this by changing zones without changing clocks at the
# previously-appointed fall back time.
#
# Decreto-Lei 309/76 of 1976-04-27 acknowledged that those international
# contacts had returned to adopting seasonal times, and considered that the
# year-round advancement "entails considerable sacrifices for the vast majority
# of the working population during the winter months", including morning
# visibility concerns for schoolchildren. It specified, beginning 1976-09-26
# 01:00, an annual return to UT+00 on the mainland from 00:00 UT on Sep lastSun
# to 00:00 UT on Mar lastSun (unless the latter date fell on Easter, in which
# case it was to be brought forward to the preceding Sunday). It also assigned
# the Permanent Time Commission to study and propose revisions for the Azores
# and Madeira, neither of which resumed DST until 1982 (as described further
# below).
# https://dre.pt/dr/detalhe/decreto-lei/309-1976-502063
Rule Port 1976 only - Sep lastSun 1:00 0 -
Rule Port 1977 only - Mar lastSun 0:00s 1:00 S
Rule Port 1977 only - Sep lastSun 0:00s 0 -
# From Tim Parenti (2024-07-01):
# Beginning in 1978, rather than triggering the Easter rule of the 1976 decree
# (Easter fell on 1978-03-26), Article 5 was used instead, which allowed DST
# dates to be changed by order of the Minister of Education and Scientific
# Research, upon consultation with the Permanent Time Commission, "whenever
# considered convenient." As such, a series of one-off ordinances were
# promulgated for the mainland in 1978 through 1980, after which the 1976
# decree naturally came back into force from 1981.
Rule Port 1978 1980 - Apr Sun>=1 1:00s 1:00 S
Rule Port 1978 only - Oct 1 1:00s 0 -
Rule Port 1979 1980 - Sep lastSun 1:00s 0 -
Rule Port 1981 1986 - Mar lastSun 0:00s 1:00 S
Rule Port 1981 1985 - Sep lastSun 0:00s 0 -
# From Tim Parenti (2024-07-01):
# Decreto-Lei 44-B/86 of 1986-03-07 switched mainland Portugal's transition
# times from 0:00s to 1:00u to harmonize with the EEC from 1986-03-30.
# https://dre.pt/dr/detalhe/decreto-lei/44-b-1986-628280
# (Transitions of 1:00s as previously reported and used by the W-Eur rules,
# though equivalent, appear to have been fiction here.) Madeira continued to
# use 0:00s for spring 1986 before joining with the mainland using 1:00u in the
# fall; meanwhile, in the Azores the two were equivalent, so the law specifying
# 0:00s wasn't touched until 1992. (See below for more on the islands.)
#
# From Rui Pedro Salgueiro (1992-11-12):
# Portugal has recently (September, 27) changed timezone
# (from WET to MET or CET) to harmonize with EEC.
#
# Martin Bruckmann (1996-02-29) reports via Peter Ilieve
# that Portugal is reverting to 0:00 by not moving its clocks this spring.
# The new Prime Minister was fed up with getting up in the dark in the winter.
#
# From Paul Eggert (1996-11-12):
# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions
# at 02:00u, not 01:00u. Assume that these are typos.
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
#STDOFF -0:36:44.68
Zone Europe/Lisbon -0:36:45 - LMT 1884
-0:36:45 - LMT 1912 Jan 1 0:00u # Lisbon MT
0:00 Port WE%sT 1966 Apr 3 2:00
0:00 Port WE%sT 1966 Oct 2 2:00s
1:00 - CET 1976 Sep 26 1:00
0:00 Port WE%sT 1983 Sep 25 1:00s
0:00 W-Eur WE%sT 1992 Sep 27 1:00s
0:00 Port WE%sT 1986
0:00 EU WE%sT 1992 Sep 27 1:00u
1:00 EU CE%sT 1996 Mar 31 1:00u
0:00 EU WE%sT
# From Tim Parenti (2024-07-01):
# For the Azores and Madeira, legislation was followed from the laws currently
# in force as listed at:
# https://oal.ul.pt/hora-legal/legislacao/
# working backward through references of revocation and abrogation to
# Decreto-Lei 47233 of 1966-10-01, the last time DST was abolished across the
# mainland and its adjacent islands. Because of that reference, it is
# therefore assumed that DST rules in the islands prior to 1966 were like that
# of the mainland, though most legislation of the time didn't explicitly
# specify DST practices for the islands.
Zone Atlantic/Azores -1:42:40 - LMT 1884 # Ponta Delgada
-1:54:32 - HMT 1912 Jan 1 2:00u # Horta MT
# Vanguard section, for zic and other parsers that support %z.
# -2:00 Port %z 1966 Apr 3 2:00
# -1:00 Port %z 1983 Sep 25 1:00s
# -1:00 W-Eur %z 1992 Sep 27 1:00s
-2:00 Port %z 1966 Oct 2 2:00s
# From Tim Parenti (2024-07-01):
# While Decreto-Lei 309/76 of 1976-04-27 reintroduced DST on the mainland by
# falling back on 1976-09-26, it assigned the Permanent Time Commission to
# study and propose revisions for the Azores and Madeira. Decreto Regional
# 9/77/A of 1977-05-17 affirmed that "the legal time remained unchanged in the
# Azores" at UT-1, and would remain there year-round.
# https://dre.pt/dr/detalhe/decreto-regional/9-1977-252066
#
# Decreto Regional 2/82/A, published 1982-03-02, adopted DST in the same
# fashion as the mainland used at the time.
# https://dre.pt/dr/detalhe/decreto-regional/2-1982-599965
# Though transitions in the Azores officially remained at 0:00s through 1992,
# this was equivalent to the EU-style 1:00u adopted by the mainland in 1986, so
# model it as such.
-1:00 - %z 1982 Mar 28 0:00s
-1:00 Port %z 1986
# Rearguard section, for parsers lacking %z; see ziguard.awk.
-2:00 Port -02/-01 1942 Apr 25 22:00s
-2:00 Port +00 1942 Aug 15 22:00s
-2:00 Port -02/-01 1943 Apr 17 22:00s
-2:00 Port +00 1943 Aug 28 22:00s
-2:00 Port -02/-01 1944 Apr 22 22:00s
-2:00 Port +00 1944 Aug 26 22:00s
-2:00 Port -02/-01 1945 Apr 21 22:00s
-2:00 Port +00 1945 Aug 25 22:00s
-2:00 Port -02/-01 1966 Apr 3 2:00
-1:00 Port -01/+00 1983 Sep 25 1:00s
-1:00 W-Eur -01/+00 1992 Sep 27 1:00s
# -2:00 Port -02/-01 1942 Apr 25 22:00s
# -2:00 Port +00 1942 Aug 15 22:00s
# -2:00 Port -02/-01 1943 Apr 17 22:00s
# -2:00 Port +00 1943 Aug 28 22:00s
# -2:00 Port -02/-01 1944 Apr 22 22:00s
# -2:00 Port +00 1944 Aug 26 22:00s
# -2:00 Port -02/-01 1945 Apr 21 22:00s
# -2:00 Port +00 1945 Aug 25 22:00s
# -2:00 Port -02/-01 1966 Oct 2 2:00s
# -1:00 - -01 1982 Mar 28 0:00s
# -1:00 Port -01/+00 1986
# End of rearguard section.
0:00 EU WE%sT 1993 Mar 28 1:00u
-1:00 EU -01/+00
#
# From Paul Eggert (1996-11-12):
# IATA SSIM (1991/1992) reports that the Azores were at -1:00.
# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00.
#
# From Tim Parenti (2024-07-01):
# After mainland Portugal had shifted forward an hour from 1992-09-27, Decreto
# Legislativo Regional 29/92/A of 1992-12-23 sought to "reduce the time
# difference" by shifting the Azores forward as well from 1992-12-27. Just six
# months later, this was revoked by Decreto Legislativo Regional 9/93/A, citing
# "major changes in work habits and way of life." Though the revocation didn't
# give a transition time, it was signed Wednesday 1993-06-16; assume it took
# effect later that evening, and that an EU-style spring forward (to +01) was
# still observed in the interim on 1993-03-28.
# https://dre.pt/dr/detalhe/decreto-legislativo-regional/29-1992-621553
# https://dre.pt/dr/detalhe/decreto-legislativo-regional/9-1993-389633
-1:00 EU %z 1992 Dec 27 1:00s
0:00 EU WE%sT 1993 Jun 17 1:00u
-1:00 EU %z
Zone Atlantic/Madeira -1:07:36 - LMT 1884 # Funchal
-1:07:36 - FMT 1912 Jan 1 1:00u # Funchal MT
# Vanguard section, for zic and other parsers that support %z.
# -1:00 Port %z 1966 Apr 3 2:00
-1:00 Port %z 1966 Oct 2 2:00s
# Rearguard section, for parsers lacking %z; see ziguard.awk.
-1:00 Port -01/+00 1942 Apr 25 22:00s
-1:00 Port +01 1942 Aug 15 22:00s
-1:00 Port -01/+00 1943 Apr 17 22:00s
-1:00 Port +01 1943 Aug 28 22:00s
-1:00 Port -01/+00 1944 Apr 22 22:00s
-1:00 Port +01 1944 Aug 26 22:00s
-1:00 Port -01/+00 1945 Apr 21 22:00s
-1:00 Port +01 1945 Aug 25 22:00s
-1:00 Port -01/+00 1966 Apr 3 2:00
# -1:00 Port -01/+00 1942 Apr 25 22:00s
# -1:00 Port +01 1942 Aug 15 22:00s
# -1:00 Port -01/+00 1943 Apr 17 22:00s
# -1:00 Port +01 1943 Aug 28 22:00s
# -1:00 Port -01/+00 1944 Apr 22 22:00s
# -1:00 Port +01 1944 Aug 26 22:00s
# -1:00 Port -01/+00 1945 Apr 21 22:00s
# -1:00 Port +01 1945 Aug 25 22:00s
# -1:00 Port -01/+00 1966 Oct 2 2:00s
# End of rearguard section.
0:00 Port WE%sT 1983 Sep 25 1:00s
#
# From Tim Parenti (2024-07-01):
# Decreto Regional 5/82/M, published 1982-04-03, established DST transitions at
# 0:00u, which for Madeira is equivalent to the mainland's rules (0:00s) at the
# time. It came into effect the day following its publication, Sunday
# 1982-04-04, thus resuming Madeira's DST practice about a week later than the
# mainland and the Azores.
# https://dre.pt/dr/detalhe/decreto-regional/5-1982-608273
#
# Decreto Legislativo Regional 18/86/M, published 1986-10-01, adopted EU-style
# rules (1:00u) and entered into immediate force after being signed on
# 1986-07-31.
# https://dre.pt/dr/detalhe/decreto-legislativo-regional/18-1986-221705
0:00 - WET 1982 Apr 4
0:00 Port WE%sT 1986 Jul 31
0:00 EU WE%sT
# Romania
@@ -2433,7 +2619,7 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr
2:00 Poland EE%sT 1946 Apr 7
3:00 Russia MSK/MSD 1989 Mar 26 2:00s
2:00 Russia EE%sT 2011 Mar 27 2:00s
3:00 - +03 2014 Oct 26 2:00s
3:00 - %z 2014 Oct 26 2:00s
2:00 - EET
@@ -2683,14 +2869,14 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880
# http://publication.pravo.gov.ru/Document/View/0001201602150056
Zone Europe/Astrakhan 3:12:12 - LMT 1924 May
3:00 - +03 1930 Jun 21
4:00 Russia +04/+05 1989 Mar 26 2:00s
3:00 Russia +03/+04 1991 Mar 31 2:00s
4:00 - +04 1992 Mar 29 2:00s
3:00 Russia +03/+04 2011 Mar 27 2:00s
4:00 - +04 2014 Oct 26 2:00s
3:00 - +03 2016 Mar 27 2:00s
4:00 - +04
3:00 - %z 1930 Jun 21
4:00 Russia %z 1989 Mar 26 2:00s
3:00 Russia %z 1991 Mar 31 2:00s
4:00 - %z 1992 Mar 29 2:00s
3:00 Russia %z 2011 Mar 27 2:00s
4:00 - %z 2014 Oct 26 2:00s
3:00 - %z 2016 Mar 27 2:00s
4:00 - %z
# From Paul Eggert (2016-11-11):
# Europe/Volgograd covers:
@@ -2720,15 +2906,15 @@ Zone Europe/Astrakhan 3:12:12 - LMT 1924 May
# http://publication.pravo.gov.ru/Document/View/0001202012220002
Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3
3:00 - +03 1930 Jun 21
4:00 - +04 1961 Nov 11
4:00 Russia +04/+05 1988 Mar 27 2:00s
3:00 - %z 1930 Jun 21
4:00 - %z 1961 Nov 11
4:00 Russia %z 1988 Mar 27 2:00s
3:00 Russia MSK/MSD 1991 Mar 31 2:00s
4:00 - +04 1992 Mar 29 2:00s
4:00 - %z 1992 Mar 29 2:00s
3:00 Russia MSK/MSD 2011 Mar 27 2:00s
4:00 - MSK 2014 Oct 26 2:00s
3:00 - MSK 2018 Oct 28 2:00s
4:00 - +04 2020 Dec 27 2:00s
4:00 - %z 2020 Dec 27 2:00s
3:00 - MSK
# From Paul Eggert (2016-11-11):
@@ -2743,14 +2929,14 @@ Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3
# http://publication.pravo.gov.ru/Document/View/0001201611220031
Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u
3:00 - +03 1930 Jun 21
4:00 Russia +04/+05 1988 Mar 27 2:00s
3:00 Russia +03/+04 1991 Mar 31 2:00s
4:00 - +04 1992 Mar 29 2:00s
3:00 Russia +03/+04 2011 Mar 27 2:00s
4:00 - +04 2014 Oct 26 2:00s
3:00 - +03 2016 Dec 4 2:00s
4:00 - +04
3:00 - %z 1930 Jun 21
4:00 Russia %z 1988 Mar 27 2:00s
3:00 Russia %z 1991 Mar 31 2:00s
4:00 - %z 1992 Mar 29 2:00s
3:00 Russia %z 2011 Mar 27 2:00s
4:00 - %z 2014 Oct 26 2:00s
3:00 - %z 2016 Dec 4 2:00s
4:00 - %z
# From Paul Eggert (2016-03-18):
# Europe/Kirov covers:
@@ -2758,10 +2944,10 @@ Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u
# The 1989 transition is from USSR act No. 227 (1989-03-14).
#
Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u
3:00 - +03 1930 Jun 21
4:00 Russia +04/+05 1989 Mar 26 2:00s
3:00 - %z 1930 Jun 21
4:00 Russia %z 1989 Mar 26 2:00s
3:00 Russia MSK/MSD 1991 Mar 31 2:00s
4:00 - +04 1992 Mar 29 2:00s
4:00 - %z 1992 Mar 29 2:00s
3:00 Russia MSK/MSD 2011 Mar 27 2:00s
4:00 - MSK 2014 Oct 26 2:00s
3:00 - MSK
@@ -2776,15 +2962,15 @@ Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u
# The 1989 transition is from USSR act No. 227 (1989-03-14).
Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u
3:00 - +03 1930 Jun 21
4:00 - +04 1935 Jan 27
4:00 Russia +04/+05 1989 Mar 26 2:00s
3:00 Russia +03/+04 1991 Mar 31 2:00s
2:00 Russia +02/+03 1991 Sep 29 2:00s
3:00 - +03 1991 Oct 20 3:00
4:00 Russia +04/+05 2010 Mar 28 2:00s
3:00 Russia +03/+04 2011 Mar 27 2:00s
4:00 - +04
3:00 - %z 1930 Jun 21
4:00 - %z 1935 Jan 27
4:00 Russia %z 1989 Mar 26 2:00s
3:00 Russia %z 1991 Mar 31 2:00s
2:00 Russia %z 1991 Sep 29 2:00s
3:00 - %z 1991 Oct 20 3:00
4:00 Russia %z 2010 Mar 28 2:00s
3:00 Russia %z 2011 Mar 27 2:00s
4:00 - %z
# From Paul Eggert (2016-03-18):
# Europe/Ulyanovsk covers:
@@ -2800,14 +2986,14 @@ Zone Europe/Samara 3:20:20 - LMT 1919 Jul 1 0:00u
# http://publication.pravo.gov.ru/Document/View/0001201603090051
Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u
3:00 - +03 1930 Jun 21
4:00 Russia +04/+05 1989 Mar 26 2:00s
3:00 Russia +03/+04 1991 Mar 31 2:00s
2:00 Russia +02/+03 1992 Jan 19 2:00s
3:00 Russia +03/+04 2011 Mar 27 2:00s
4:00 - +04 2014 Oct 26 2:00s
3:00 - +03 2016 Mar 27 2:00s
4:00 - +04
3:00 - %z 1930 Jun 21
4:00 Russia %z 1989 Mar 26 2:00s
3:00 Russia %z 1991 Mar 31 2:00s
2:00 Russia %z 1992 Jan 19 2:00s
3:00 Russia %z 2011 Mar 27 2:00s
4:00 - %z 2014 Oct 26 2:00s
3:00 - %z 2016 Mar 27 2:00s
4:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
# Asia/Yekaterinburg covers...
@@ -2832,12 +3018,12 @@ Zone Europe/Ulyanovsk 3:13:36 - LMT 1919 Jul 1 0:00u
#STDOFF 4:02:32.9
Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3
3:45:05 - PMT 1919 Jul 15 4:00
4:00 - +04 1930 Jun 21
5:00 Russia +05/+06 1991 Mar 31 2:00s
4:00 Russia +04/+05 1992 Jan 19 2:00s
5:00 Russia +05/+06 2011 Mar 27 2:00s
6:00 - +06 2014 Oct 26 2:00s
5:00 - +05
4:00 - %z 1930 Jun 21
5:00 Russia %z 1991 Mar 31 2:00s
4:00 Russia %z 1992 Jan 19 2:00s
5:00 Russia %z 2011 Mar 27 2:00s
6:00 - %z 2014 Oct 26 2:00s
5:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
@@ -2847,12 +3033,12 @@ Zone Asia/Yekaterinburg 4:02:33 - LMT 1916 Jul 3
# Byalokoz 1919 says Omsk was 4:53:30.
Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14
5:00 - +05 1930 Jun 21
6:00 Russia +06/+07 1991 Mar 31 2:00s
5:00 Russia +05/+06 1992 Jan 19 2:00s
6:00 Russia +06/+07 2011 Mar 27 2:00s
7:00 - +07 2014 Oct 26 2:00s
6:00 - +06
5:00 - %z 1930 Jun 21
6:00 Russia %z 1991 Mar 31 2:00s
5:00 Russia %z 1992 Jan 19 2:00s
6:00 Russia %z 2011 Mar 27 2:00s
7:00 - %z 2014 Oct 26 2:00s
6:00 - %z
# From Paul Eggert (2016-02-22):
# Asia/Barnaul covers:
@@ -2885,14 +3071,14 @@ Zone Asia/Omsk 4:53:30 - LMT 1919 Nov 14
# http://publication.pravo.gov.ru/Document/View/0001201603090038
Zone Asia/Barnaul 5:35:00 - LMT 1919 Dec 10
6:00 - +06 1930 Jun 21
7:00 Russia +07/+08 1991 Mar 31 2:00s
6:00 Russia +06/+07 1992 Jan 19 2:00s
7:00 Russia +07/+08 1995 May 28
6:00 Russia +06/+07 2011 Mar 27 2:00s
7:00 - +07 2014 Oct 26 2:00s
6:00 - +06 2016 Mar 27 2:00s
7:00 - +07
6:00 - %z 1930 Jun 21
7:00 Russia %z 1991 Mar 31 2:00s
6:00 Russia %z 1992 Jan 19 2:00s
7:00 Russia %z 1995 May 28
6:00 Russia %z 2011 Mar 27 2:00s
7:00 - %z 2014 Oct 26 2:00s
6:00 - %z 2016 Mar 27 2:00s
7:00 - %z
# From Paul Eggert (2016-03-18):
# Asia/Novosibirsk covers:
@@ -2906,14 +3092,14 @@ Zone Asia/Barnaul 5:35:00 - LMT 1919 Dec 10
# http://publication.pravo.gov.ru/Document/View/0001201607040064
Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00
6:00 - +06 1930 Jun 21
7:00 Russia +07/+08 1991 Mar 31 2:00s
6:00 Russia +06/+07 1992 Jan 19 2:00s
7:00 Russia +07/+08 1993 May 23 # say Shanks & P.
6:00 Russia +06/+07 2011 Mar 27 2:00s
7:00 - +07 2014 Oct 26 2:00s
6:00 - +06 2016 Jul 24 2:00s
7:00 - +07
6:00 - %z 1930 Jun 21
7:00 Russia %z 1991 Mar 31 2:00s
6:00 Russia %z 1992 Jan 19 2:00s
7:00 Russia %z 1993 May 23 # say Shanks & P.
6:00 Russia %z 2011 Mar 27 2:00s
7:00 - %z 2014 Oct 26 2:00s
6:00 - %z 2016 Jul 24 2:00s
7:00 - %z
# From Paul Eggert (2016-03-18):
# Asia/Tomsk covers:
@@ -2958,14 +3144,14 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00
# http://publication.pravo.gov.ru/Document/View/0001201604260048
Zone Asia/Tomsk 5:39:51 - LMT 1919 Dec 22
6:00 - +06 1930 Jun 21
7:00 Russia +07/+08 1991 Mar 31 2:00s
6:00 Russia +06/+07 1992 Jan 19 2:00s
7:00 Russia +07/+08 2002 May 1 3:00
6:00 Russia +06/+07 2011 Mar 27 2:00s
7:00 - +07 2014 Oct 26 2:00s
6:00 - +06 2016 May 29 2:00s
7:00 - +07
6:00 - %z 1930 Jun 21
7:00 Russia %z 1991 Mar 31 2:00s
6:00 Russia %z 1992 Jan 19 2:00s
7:00 Russia %z 2002 May 1 3:00
6:00 Russia %z 2011 Mar 27 2:00s
7:00 - %z 2014 Oct 26 2:00s
6:00 - %z 2016 May 29 2:00s
7:00 - %z
# From Tim Parenti (2014-07-03):
@@ -2996,12 +3182,12 @@ Zone Asia/Tomsk 5:39:51 - LMT 1919 Dec 22
# realigning itself with KRAT.
Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1
6:00 - +06 1930 Jun 21
7:00 Russia +07/+08 1991 Mar 31 2:00s
6:00 Russia +06/+07 1992 Jan 19 2:00s
7:00 Russia +07/+08 2010 Mar 28 2:00s
6:00 Russia +06/+07 2011 Mar 27 2:00s
7:00 - +07
6:00 - %z 1930 Jun 21
7:00 Russia %z 1991 Mar 31 2:00s
6:00 Russia %z 1992 Jan 19 2:00s
7:00 Russia %z 2010 Mar 28 2:00s
6:00 Russia %z 2011 Mar 27 2:00s
7:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
# Asia/Krasnoyarsk covers...
@@ -3015,12 +3201,12 @@ Zone Asia/Novokuznetsk 5:48:48 - LMT 1924 May 1
# Byalokoz 1919 says Krasnoyarsk was 6:11:26.
Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6
6:00 - +06 1930 Jun 21
7:00 Russia +07/+08 1991 Mar 31 2:00s
6:00 Russia +06/+07 1992 Jan 19 2:00s
7:00 Russia +07/+08 2011 Mar 27 2:00s
8:00 - +08 2014 Oct 26 2:00s
7:00 - +07
6:00 - %z 1930 Jun 21
7:00 Russia %z 1991 Mar 31 2:00s
6:00 Russia %z 1992 Jan 19 2:00s
7:00 Russia %z 2011 Mar 27 2:00s
8:00 - %z 2014 Oct 26 2:00s
7:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
@@ -3037,12 +3223,12 @@ Zone Asia/Krasnoyarsk 6:11:26 - LMT 1920 Jan 6
Zone Asia/Irkutsk 6:57:05 - LMT 1880
6:57:05 - IMT 1920 Jan 25 # Irkutsk Mean Time
7:00 - +07 1930 Jun 21
8:00 Russia +08/+09 1991 Mar 31 2:00s
7:00 Russia +07/+08 1992 Jan 19 2:00s
8:00 Russia +08/+09 2011 Mar 27 2:00s
9:00 - +09 2014 Oct 26 2:00s
8:00 - +08
7:00 - %z 1930 Jun 21
8:00 Russia %z 1991 Mar 31 2:00s
7:00 Russia %z 1992 Jan 19 2:00s
8:00 Russia %z 2011 Mar 27 2:00s
9:00 - %z 2014 Oct 26 2:00s
8:00 - %z
# From Tim Parenti (2014-07-06):
@@ -3059,13 +3245,13 @@ Zone Asia/Irkutsk 6:57:05 - LMT 1880
# http://publication.pravo.gov.ru/Document/View/0001201512300107
Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15
8:00 - +08 1930 Jun 21
9:00 Russia +09/+10 1991 Mar 31 2:00s
8:00 Russia +08/+09 1992 Jan 19 2:00s
9:00 Russia +09/+10 2011 Mar 27 2:00s
10:00 - +10 2014 Oct 26 2:00s
8:00 - +08 2016 Mar 27 2:00
9:00 - +09
8:00 - %z 1930 Jun 21
9:00 Russia %z 1991 Mar 31 2:00s
8:00 Russia %z 1992 Jan 19 2:00s
9:00 Russia %z 2011 Mar 27 2:00s
10:00 - %z 2014 Oct 26 2:00s
8:00 - %z 2016 Mar 27 2:00
9:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
@@ -3105,12 +3291,12 @@ Zone Asia/Chita 7:33:52 - LMT 1919 Dec 15
# Byalokoz 1919 says Yakutsk was 8:38:58.
Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15
8:00 - +08 1930 Jun 21
9:00 Russia +09/+10 1991 Mar 31 2:00s
8:00 Russia +08/+09 1992 Jan 19 2:00s
9:00 Russia +09/+10 2011 Mar 27 2:00s
10:00 - +10 2014 Oct 26 2:00s
9:00 - +09
8:00 - %z 1930 Jun 21
9:00 Russia %z 1991 Mar 31 2:00s
8:00 Russia %z 1992 Jan 19 2:00s
9:00 Russia %z 2011 Mar 27 2:00s
10:00 - %z 2014 Oct 26 2:00s
9:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
@@ -3128,12 +3314,12 @@ Zone Asia/Yakutsk 8:38:58 - LMT 1919 Dec 15
# Go with Byalokoz.
Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15
9:00 - +09 1930 Jun 21
10:00 Russia +10/+11 1991 Mar 31 2:00s
9:00 Russia +09/+10 1992 Jan 19 2:00s
10:00 Russia +10/+11 2011 Mar 27 2:00s
11:00 - +11 2014 Oct 26 2:00s
10:00 - +10
9:00 - %z 1930 Jun 21
10:00 Russia %z 1991 Mar 31 2:00s
9:00 Russia %z 1992 Jan 19 2:00s
10:00 Russia %z 2011 Mar 27 2:00s
11:00 - %z 2014 Oct 26 2:00s
10:00 - %z
# From Tim Parenti (2014-07-03):
@@ -3151,14 +3337,14 @@ Zone Asia/Vladivostok 8:47:31 - LMT 1922 Nov 15
# This transition is no doubt wrong, but we have no better info.
Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15
8:00 - +08 1930 Jun 21
9:00 Russia +09/+10 1991 Mar 31 2:00s
8:00 Russia +08/+09 1992 Jan 19 2:00s
9:00 Russia +09/+10 2004
10:00 Russia +10/+11 2011 Mar 27 2:00s
11:00 - +11 2011 Sep 13 0:00s # Decree 725?
10:00 - +10 2014 Oct 26 2:00s
9:00 - +09
8:00 - %z 1930 Jun 21
9:00 Russia %z 1991 Mar 31 2:00s
8:00 Russia %z 1992 Jan 19 2:00s
9:00 Russia %z 2004
10:00 Russia %z 2011 Mar 27 2:00s
11:00 - %z 2011 Sep 13 0:00s # Decree 725?
10:00 - %z 2014 Oct 26 2:00s
9:00 - %z
# From Tim Parenti (2014-07-03):
@@ -3174,14 +3360,14 @@ Zone Asia/Khandyga 9:02:13 - LMT 1919 Dec 15
# The Zone name should be Asia/Yuzhno-Sakhalinsk, but that's too long.
Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23
9:00 - +09 1945 Aug 25
11:00 Russia +11/+12 1991 Mar 31 2:00s # Sakhalin T
10:00 Russia +10/+11 1992 Jan 19 2:00s
11:00 Russia +11/+12 1997 Mar lastSun 2:00s
10:00 Russia +10/+11 2011 Mar 27 2:00s
11:00 - +11 2014 Oct 26 2:00s
10:00 - +10 2016 Mar 27 2:00s
11:00 - +11
9:00 - %z 1945 Aug 25
11:00 Russia %z 1991 Mar 31 2:00s # Sakhalin T
10:00 Russia %z 1992 Jan 19 2:00s
11:00 Russia %z 1997 Mar lastSun 2:00s
10:00 Russia %z 2011 Mar 27 2:00s
11:00 - %z 2014 Oct 26 2:00s
10:00 - %z 2016 Mar 27 2:00s
11:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2009-11-29):
@@ -3204,13 +3390,13 @@ Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23
# http://publication.pravo.gov.ru/Document/View/0001201604050038
Zone Asia/Magadan 10:03:12 - LMT 1924 May 2
10:00 - +10 1930 Jun 21 # Magadan Time
11:00 Russia +11/+12 1991 Mar 31 2:00s
10:00 Russia +10/+11 1992 Jan 19 2:00s
11:00 Russia +11/+12 2011 Mar 27 2:00s
12:00 - +12 2014 Oct 26 2:00s
10:00 - +10 2016 Apr 24 2:00s
11:00 - +11
10:00 - %z 1930 Jun 21 # Magadan Time
11:00 Russia %z 1991 Mar 31 2:00s
10:00 Russia %z 1992 Jan 19 2:00s
11:00 Russia %z 2011 Mar 27 2:00s
12:00 - %z 2014 Oct 26 2:00s
10:00 - %z 2016 Apr 24 2:00s
11:00 - %z
# From Tim Parenti (2014-07-06):
@@ -3255,12 +3441,12 @@ Zone Asia/Magadan 10:03:12 - LMT 1924 May 2
# Go with Srednekolymsk.
Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2
10:00 - +10 1930 Jun 21
11:00 Russia +11/+12 1991 Mar 31 2:00s
10:00 Russia +10/+11 1992 Jan 19 2:00s
11:00 Russia +11/+12 2011 Mar 27 2:00s
12:00 - +12 2014 Oct 26 2:00s
11:00 - +11
10:00 - %z 1930 Jun 21
11:00 Russia %z 1991 Mar 31 2:00s
10:00 Russia %z 1992 Jan 19 2:00s
11:00 Russia %z 2011 Mar 27 2:00s
12:00 - %z 2014 Oct 26 2:00s
11:00 - %z
# From Tim Parenti (2014-07-03):
@@ -3278,14 +3464,14 @@ Zone Asia/Srednekolymsk 10:14:52 - LMT 1924 May 2
# UTC+12 since at least then, too.
Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15
8:00 - +08 1930 Jun 21
9:00 Russia +09/+10 1981 Apr 1
11:00 Russia +11/+12 1991 Mar 31 2:00s
10:00 Russia +10/+11 1992 Jan 19 2:00s
11:00 Russia +11/+12 2011 Mar 27 2:00s
12:00 - +12 2011 Sep 13 0:00s # Decree 725?
11:00 - +11 2014 Oct 26 2:00s
10:00 - +10
8:00 - %z 1930 Jun 21
9:00 Russia %z 1981 Apr 1
11:00 Russia %z 1991 Mar 31 2:00s
10:00 Russia %z 1992 Jan 19 2:00s
11:00 Russia %z 2011 Mar 27 2:00s
12:00 - %z 2011 Sep 13 0:00s # Decree 725?
11:00 - %z 2014 Oct 26 2:00s
10:00 - %z
# From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25):
@@ -3298,12 +3484,12 @@ Zone Asia/Ust-Nera 9:32:54 - LMT 1919 Dec 15
# The Zone name should be Asia/Petropavlovsk-Kamchatski or perhaps
# Asia/Petropavlovsk-Kamchatsky, but these are too long.
Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10
11:00 - +11 1930 Jun 21
12:00 Russia +12/+13 1991 Mar 31 2:00s
11:00 Russia +11/+12 1992 Jan 19 2:00s
12:00 Russia +12/+13 2010 Mar 28 2:00s
11:00 Russia +11/+12 2011 Mar 27 2:00s
12:00 - +12
11:00 - %z 1930 Jun 21
12:00 Russia %z 1991 Mar 31 2:00s
11:00 Russia %z 1992 Jan 19 2:00s
12:00 Russia %z 2010 Mar 28 2:00s
11:00 Russia %z 2011 Mar 27 2:00s
12:00 - %z
# From Tim Parenti (2014-07-03):
@@ -3311,13 +3497,13 @@ Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10
# 87 RU-CHU Chukotka Autonomous Okrug
Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2
12:00 - +12 1930 Jun 21
13:00 Russia +13/+14 1982 Apr 1 0:00s
12:00 Russia +12/+13 1991 Mar 31 2:00s
11:00 Russia +11/+12 1992 Jan 19 2:00s
12:00 Russia +12/+13 2010 Mar 28 2:00s
11:00 Russia +11/+12 2011 Mar 27 2:00s
12:00 - +12
12:00 - %z 1930 Jun 21
13:00 Russia %z 1982 Apr 1 0:00s
12:00 Russia %z 1991 Mar 31 2:00s
11:00 Russia %z 1992 Jan 19 2:00s
12:00 Russia %z 2010 Mar 28 2:00s
11:00 Russia %z 2011 Mar 27 2:00s
12:00 - %z
# Bosnia & Herzegovina
# Croatia
@@ -3436,7 +3622,7 @@ Zone Africa/Ceuta -0:21:16 - LMT 1901 Jan 1 0:00u
1:00 - CET 1986
1:00 EU CE%sT
Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C.
-1:00 - -01 1946 Sep 30 1:00
-1:00 - %z 1946 Sep 30 1:00
0:00 - WET 1980 Apr 6 0:00s
0:00 1:00 WEST 1980 Sep 28 1:00u
0:00 EU WE%sT
@@ -3517,8 +3703,8 @@ Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C.
# but if no one is present after 11 at night, could be postponed until one
# hour before the beginning of service.
# From Paul Eggert (2013-09-11):
# Round BMT to the nearest even second, 0:29:46.
# From Paul Eggert (2024-05-24):
# Express BMT as 0:29:45.500, approximately the same precision 7° 26' 22.50".
#
# We can find no reliable source for Shanks's assertion that all of Switzerland
# except Geneva switched to Bern Mean Time at 00:00 on 1848-09-12. This book:
@@ -3557,6 +3743,7 @@ Rule Swiss 1941 1942 - May Mon>=1 1:00 1:00 S
Rule Swiss 1941 1942 - Oct Mon>=1 2:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment.
#STDOFF 0:29:45.500
0:29:46 - BMT 1894 Jun # Bern Mean Time
1:00 Swiss CE%sT 1981
1:00 EU CE%sT
@@ -3754,7 +3941,7 @@ Rule Turkey 1996 2006 - Oct lastSun 1:00s 0 -
Zone Europe/Istanbul 1:55:52 - LMT 1880
1:56:56 - IMT 1910 Oct # Istanbul Mean Time?
2:00 Turkey EE%sT 1978 Jun 29
3:00 Turkey +03/+04 1984 Nov 1 2:00
3:00 Turkey %z 1984 Nov 1 2:00
2:00 Turkey EE%sT 2007
2:00 EU EE%sT 2011 Mar 27 1:00u
2:00 - EET 2011 Mar 28 1:00u
@@ -3763,7 +3950,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880
2:00 EU EE%sT 2015 Oct 25 1:00u
2:00 1:00 EEST 2015 Nov 8 1:00u
2:00 EU EE%sT 2016 Sep 7
3:00 - +03
3:00 - %z
# Ukraine
#

View File

@@ -92,11 +92,11 @@ Leap 2016 Dec 31 23:59:60 + S
# Any additional leap seconds will come after this.
# This Expires line is commented out for now,
# so that pre-2020a zic implementations do not reject this file.
#Expires 2024 Dec 28 00:00:00
#Expires 2025 Jun 28 00:00:00
# POSIX timestamps for the data in this file:
#updated 1704708379 (2024-01-08 10:06:19 UTC)
#expires 1735344000 (2024-12-28 00:00:00 UTC)
#updated 1720104763 (2024-07-04 14:52:43 UTC)
#expires 1751068800 (2025-06-28 00:00:00 UTC)
# Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat)
# File expires on 28 December 2024
# File expires on 28 June 2025

View File

@@ -208,26 +208,6 @@ Rule US 1987 2006 - Apr Sun>=1 2:00 1:00 D
Rule US 2007 max - Mar Sun>=8 2:00 1:00 D
Rule US 2007 max - Nov Sun>=1 2:00 0 S
# From Arthur David Olson, 2005-12-19
# We generate the files specified below to guard against old files with
# obsolete information being left in the time zone binary directory.
# We limit the list to names that have appeared in previous versions of
# this time zone package.
# We do these as separate Zones rather than as Links to avoid problems if
# a particular place changes whether it observes DST.
# We put these specifications here in the northamerica file both to
# increase the chances that they'll actually get compiled and to
# avoid the need to duplicate the US rules in another file.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone EST -5:00 - EST
Zone MST -7:00 - MST
Zone HST -10:00 - HST
Zone EST5EDT -5:00 US E%sT
Zone CST6CDT -6:00 US C%sT
Zone MST7MDT -7:00 US M%sT
Zone PST8PDT -8:00 US P%sT
# From U. S. Naval Observatory (1989-01-19):
# USA EASTERN 5 H BEHIND UTC NEW YORK, WASHINGTON
# USA EASTERN 4 H BEHIND UTC APR 3 - OCT 30
@@ -2396,6 +2376,81 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20
# the researchers who prepared the Decrees page failed to find some of
# the relevant documents.
# From Heitor David Pinto (2024-08-04):
# In 1931, the decree implementing DST specified that it would take
# effect on 30 April....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=192270&pagina=2&seccion=1
#
# In 1981, the decree changing Campeche, Yucatán and Quintana Roo to UTC-5
# specified that it would enter into force on 26 December 1981 at 2:00....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4705667&fecha=23/12/1981&cod_diario=202796
#
# In 1982, the decree returning Campeche and Yucatán to UTC-6 specified that
# it would enter into force on 2 November 1982 at 2:00....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=205689&pagina=3&seccion=0
#
# Quintana Roo changed to UTC-6 on 4 January 1983 at 0:00, and again
# to UTC-5 on 26 October 1997 at 2:00....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4787355&fecha=28/12/1982&cod_diario=206112
# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=209559&pagina=15&seccion=0
#
# Durango, Coahuila, Nuevo León and Tamaulipas were set to UTC-7 on 1 January
# 1922, and changed to UTC-6 on 10 June 1927. Then Durango, Coahuila and
# Nuevo León (but not Tamaulipas) returned to UTC-7 on 15 November 1930,
# observed DST in 1931, and changed again to UTC-6 on 1 April 1932....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4441846&fecha=29/12/1921&cod_diario=187468
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4541520&fecha=09/06/1927&cod_diario=193920
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4491963&fecha=15/11/1930&cod_diario=190835
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4418437&fecha=21/01/1932&cod_diario=185588
#
# ... the ... 10 June 1927 ... decree only said 10 June 1927, without
# specifying a time, so I suppose that it should be considered at 0:00.
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4541520&fecha=09/06/1927&cod_diario=193920
#
# In 1942, the decree changing Baja California, Baja California Sur, Sonora,
# Sinaloa and Nayarit to UTC-7 was published on 24 April, but it said that it
# would apply from 1 April, so it's unclear when the change actually
# occurred. The database currently shows 24 April 1942.
# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=192203&pagina=2&seccion=1
#
# Baja California Sur, Sonora, Sinaloa and Nayarit never used UTC-8. The ...
# 14 January 1949 ... change [to UTC-8] only occurred in Baja California.
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4515613&fecha=13/01/1949&cod_diario=192309
#
# In 1945, the decree changing Baja California to UTC-8 specified that it
# would take effect on the third day from its publication.
# It was published on 12 November, so it would take effect on 15 November....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4555049&fecha=12/11/1945&cod_diario=194763
#
# In 1948, the decree changing Baja California to UTC-7 specified that it
# would take effect on "this date". The decree was made on 13 March,
# but published on 5 April, so it's unclear when the change actually occurred.
# The database currently shows 5 April 1948.
# https://www.dof.gob.mx/nota_to_imagen_fs.php?cod_diario=188624&pagina=2&seccion=0
#
# In 1949, the decree changing Baja California to UTC-8 was published on 13
# January, but it said that it would apply from 1 January, so it's unclear when
# the change actually occurred. The database currently shows 14 January 1949.
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4515613&fecha=13/01/1949&cod_diario=192309
#
# Baja California also observed UTC-7 from 1 May to 24 September 1950,
# from 29 April to 30 September 1951 at 2:00,
# and from 27 April to 28 September 1952 at 2:00....
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4600403&fecha=29/04/1950&cod_diario=197505
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4623553&fecha=23/09/1950&cod_diario=198805
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4469444&fecha=27/04/1951&cod_diario=189317
# https://www.dof.gob.mx/nota_to_imagen_fs.php?codnota=4533868&fecha=10/03/1952&cod_diario=193465
#
# All changes in Baja California from 1948 to 1952 match those in California,
# on the same dates or with a difference of one day.
# So it may be easier to implement these changes as DST with rule CA
# during this whole period.
#
# From Paul Eggert (2024-08-18):
# For now, maintain the slightly-different history for Baja California,
# as we have no information on whether 1948/1952 clocks in Tijuana followed
# the decrees or followed San Diego.
# From Alan Perry (1996-02-15):
# A guy from our Mexico subsidiary finally found the Presidential Decree
# outlining the timezone changes in Mexico.
@@ -2599,7 +2654,7 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20
# http://puentelibre.mx/noticia/ciudad_juarez_cambio_horario_noviembre_2022/
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Mexico 1931 only - May 1 23:00 1:00 D
Rule Mexico 1931 only - April 30 0:00 1:00 D
Rule Mexico 1931 only - Oct 1 0:00 0 S
Rule Mexico 1939 only - Feb 5 0:00 1:00 D
Rule Mexico 1939 only - Jun 25 0:00 0 S
@@ -2618,14 +2673,16 @@ Rule Mexico 2002 2022 - Oct lastSun 2:00 0 S
# Zone NAME STDOFF RULES FORMAT [UNTIL]
# Quintana Roo; represented by Cancún
Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u
-6:00 - CST 1981 Dec 23
-6:00 - CST 1981 Dec 26 2:00
-5:00 - EST 1983 Jan 4 0:00
-6:00 Mexico C%sT 1997 Oct 26 2:00
-5:00 Mexico E%sT 1998 Aug 2 2:00
-6:00 Mexico C%sT 2015 Feb 1 2:00
-5:00 - EST
# Campeche, Yucatán; represented by Mérida
Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u
-6:00 - CST 1981 Dec 23
-5:00 - EST 1982 Dec 2
-6:00 - CST 1981 Dec 26 2:00
-5:00 - EST 1982 Nov 2 2:00
-6:00 Mexico C%sT
# Coahuila, Nuevo León, Tamaulipas (near US border)
# This includes the following municipios:
@@ -2642,12 +2699,15 @@ Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u
-6:00 US C%sT
# Durango; Coahuila, Nuevo León, Tamaulipas (away from US border)
Zone America/Monterrey -6:41:16 - LMT 1922 Jan 1 6:00u
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1988
-6:00 US C%sT 1989
-6:00 Mexico C%sT
# Central Mexico
Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 Mexico C%sT 2001 Sep 30 2:00
@@ -2658,7 +2718,7 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u
# Práxedis G Guerrero.
# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf
Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1996
@@ -2673,7 +2733,7 @@ Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u
# Benavides.
# http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf
Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1996
@@ -2685,7 +2745,7 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u
-6:00 US C%sT
# Chihuahua (away from US border)
Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1996
@@ -2695,23 +2755,21 @@ Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u
-6:00 - CST
# Sonora
Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1942 Apr 24
-7:00 - MST 1949 Jan 14
-8:00 - PST 1970
-7:00 - MST 1996
-7:00 Mexico M%sT 1999
-7:00 - MST
# Baja California Sur, Nayarit (except Bahía de Banderas), Sinaloa
Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1942 Apr 24
-7:00 - MST 1949 Jan 14
-8:00 - PST 1970
-7:00 - MST 1970
-7:00 Mexico M%sT
# Bahía de Banderas
@@ -2744,27 +2802,32 @@ Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u
# Use "Bahia_Banderas" to keep the name to fourteen characters.
Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1927 Jun 10 23:00
-7:00 - MST 1927 Jun 10
-6:00 - CST 1930 Nov 15
-7:00 Mexico M%sT 1932 Apr 1
-6:00 - CST 1942 Apr 24
-7:00 - MST 1949 Jan 14
-8:00 - PST 1970
-7:00 - MST 1970
-7:00 Mexico M%sT 2010 Apr 4 2:00
-6:00 Mexico C%sT
# Baja California
Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u
-7:00 - MST 1924
-8:00 - PST 1927 Jun 10 23:00
-8:00 - PST 1927 Jun 10
-7:00 - MST 1930 Nov 15
-8:00 - PST 1931 Apr 1
-8:00 1:00 PDT 1931 Sep 30
-8:00 - PST 1942 Apr 24
-8:00 1:00 PWT 1945 Aug 14 23:00u
-8:00 1:00 PPT 1945 Nov 12 # Peace
-8:00 1:00 PPT 1945 Nov 15 # Peace
-8:00 - PST 1948 Apr 5
-8:00 1:00 PDT 1949 Jan 14
-8:00 - PST 1950 May 1
-8:00 1:00 PDT 1950 Sep 24
-8:00 - PST 1951 Apr 29 2:00
-8:00 1:00 PDT 1951 Sep 30 2:00
-8:00 - PST 1952 Apr 27 2:00
-8:00 1:00 PDT 1952 Sep 28 2:00
-8:00 - PST 1954
-8:00 CA P%sT 1961
-8:00 - PST 1976
@@ -3573,8 +3636,8 @@ Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Miquelon -3:44:40 - LMT 1911 Jun 15 # St Pierre
-4:00 - AST 1980 May
-3:00 - -03 1987
-3:00 Canada -03/-02
-3:00 - %z 1987
-3:00 Canada %z
# Turks and Caicos
#

View File

@@ -425,11 +425,11 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 -
Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May # Córdoba Mean Time
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 Arg -03/-02
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 Arg %z
#
# Córdoba (CB), Santa Fe (SF), Entre Ríos (ER), Corrientes (CN), Misiones (MN),
# Chaco (CC), Formosa (FM), Santiago del Estero (SE)
@@ -444,120 +444,120 @@ Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
Zone America/Argentina/Cordoba -4:16:48 - LMT 1894 Oct 31
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1991 Mar 3
-4:00 - -04 1991 Oct 20
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 Arg -03/-02
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1991 Mar 3
-4:00 - %z 1991 Oct 20
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 Arg %z
#
# Salta (SA), La Pampa (LP), Neuquén (NQ), Rio Negro (RN)
Zone America/Argentina/Salta -4:21:40 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1991 Mar 3
-4:00 - -04 1991 Oct 20
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1991 Mar 3
-4:00 - %z 1991 Oct 20
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# Tucumán (TM)
Zone America/Argentina/Tucuman -4:20:52 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1991 Mar 3
-4:00 - -04 1991 Oct 20
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 Jun 1
-4:00 - -04 2004 Jun 13
-3:00 Arg -03/-02
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1991 Mar 3
-4:00 - %z 1991 Oct 20
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 Jun 1
-4:00 - %z 2004 Jun 13
-3:00 Arg %z
#
# La Rioja (LR)
Zone America/Argentina/La_Rioja -4:27:24 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1991 Mar 1
-4:00 - -04 1991 May 7
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 Jun 1
-4:00 - -04 2004 Jun 20
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1991 Mar 1
-4:00 - %z 1991 May 7
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 Jun 1
-4:00 - %z 2004 Jun 20
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# San Juan (SJ)
Zone America/Argentina/San_Juan -4:34:04 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1991 Mar 1
-4:00 - -04 1991 May 7
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 May 31
-4:00 - -04 2004 Jul 25
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1991 Mar 1
-4:00 - %z 1991 May 7
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 May 31
-4:00 - %z 2004 Jul 25
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# Jujuy (JY)
Zone America/Argentina/Jujuy -4:21:12 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1990 Mar 4
-4:00 - -04 1990 Oct 28
-4:00 1:00 -03 1991 Mar 17
-4:00 - -04 1991 Oct 6
-3:00 1:00 -02 1992
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1990 Mar 4
-4:00 - %z 1990 Oct 28
-4:00 1:00 %z 1991 Mar 17
-4:00 - %z 1991 Oct 6
-3:00 1:00 %z 1992
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# Catamarca (CT), Chubut (CH)
Zone America/Argentina/Catamarca -4:23:08 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1991 Mar 3
-4:00 - -04 1991 Oct 20
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 Jun 1
-4:00 - -04 2004 Jun 20
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1991 Mar 3
-4:00 - %z 1991 Oct 20
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 Jun 1
-4:00 - %z 2004 Jun 20
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# Mendoza (MZ)
Zone America/Argentina/Mendoza -4:35:16 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1990 Mar 4
-4:00 - -04 1990 Oct 15
-4:00 1:00 -03 1991 Mar 1
-4:00 - -04 1991 Oct 15
-4:00 1:00 -03 1992 Mar 1
-4:00 - -04 1992 Oct 18
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 May 23
-4:00 - -04 2004 Sep 26
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1990 Mar 4
-4:00 - %z 1990 Oct 15
-4:00 1:00 %z 1991 Mar 1
-4:00 - %z 1991 Oct 15
-4:00 1:00 %z 1992 Mar 1
-4:00 - %z 1992 Oct 18
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 May 23
-4:00 - %z 2004 Sep 26
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# San Luis (SL)
@@ -567,53 +567,53 @@ Rule SanLuis 2007 2008 - Oct Sun>=8 0:00 1:00 -
Zone America/Argentina/San_Luis -4:25:24 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1990
-3:00 1:00 -02 1990 Mar 14
-4:00 - -04 1990 Oct 15
-4:00 1:00 -03 1991 Mar 1
-4:00 - -04 1991 Jun 1
-3:00 - -03 1999 Oct 3
-4:00 1:00 -03 2000 Mar 3
-3:00 - -03 2004 May 31
-4:00 - -04 2004 Jul 25
-3:00 Arg -03/-02 2008 Jan 21
-4:00 SanLuis -04/-03 2009 Oct 11
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1990
-3:00 1:00 %z 1990 Mar 14
-4:00 - %z 1990 Oct 15
-4:00 1:00 %z 1991 Mar 1
-4:00 - %z 1991 Jun 1
-3:00 - %z 1999 Oct 3
-4:00 1:00 %z 2000 Mar 3
-3:00 - %z 2004 May 31
-4:00 - %z 2004 Jul 25
-3:00 Arg %z 2008 Jan 21
-4:00 SanLuis %z 2009 Oct 11
-3:00 - %z
#
# Santa Cruz (SC)
Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 Jun 1
-4:00 - -04 2004 Jun 20
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 Jun 1
-4:00 - %z 2004 Jun 20
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
#
# Tierra del Fuego, Antártida e Islas del Atlántico Sur (TF)
Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31
#STDOFF -4:16:48.25
-4:16:48 - CMT 1920 May
-4:00 - -04 1930 Dec
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1999 Oct 3
-4:00 Arg -04/-03 2000 Mar 3
-3:00 - -03 2004 May 30
-4:00 - -04 2004 Jun 20
-3:00 Arg -03/-02 2008 Oct 18
-3:00 - -03
-4:00 - %z 1930 Dec
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1999 Oct 3
-4:00 Arg %z 2000 Mar 3
-3:00 - %z 2004 May 30
-4:00 - %z 2004 Jun 20
-3:00 Arg %z 2008 Oct 18
-3:00 - %z
# Bolivia
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/La_Paz -4:32:36 - LMT 1890
-4:32:36 - CMT 1931 Oct 15 # Calamarca MT
-4:32:36 1:00 BST 1932 Mar 21 # Bolivia ST
-4:00 - -04
-4:00 - %z
# Brazil
@@ -984,12 +984,12 @@ Rule Brazil 2018 only - Nov Sun>=1 0:00 1:00 -
#
# Fernando de Noronha (administratively part of PE)
Zone America/Noronha -2:09:40 - LMT 1914
-2:00 Brazil -02/-01 1990 Sep 17
-2:00 - -02 1999 Sep 30
-2:00 Brazil -02/-01 2000 Oct 15
-2:00 - -02 2001 Sep 13
-2:00 Brazil -02/-01 2002 Oct 1
-2:00 - -02
-2:00 Brazil %z 1990 Sep 17
-2:00 - %z 1999 Sep 30
-2:00 Brazil %z 2000 Oct 15
-2:00 - %z 2001 Sep 13
-2:00 Brazil %z 2002 Oct 1
-2:00 - %z
# Other Atlantic islands have no permanent settlement.
# These include Trindade and Martim Vaz (administratively part of ES),
# Rocas Atoll (RN), and the St Peter and St Paul Archipelago (PE).
@@ -1002,119 +1002,119 @@ Zone America/Noronha -2:09:40 - LMT 1914
# In the north a very small part from the river Javary (now Jari I guess,
# the border with Amapá) to the Amazon, then to the Xingu.
Zone America/Belem -3:13:56 - LMT 1914
-3:00 Brazil -03/-02 1988 Sep 12
-3:00 - -03
-3:00 Brazil %z 1988 Sep 12
-3:00 - %z
#
# west Pará (PA)
# West Pará includes Altamira, Óbidos, Prainha, Oriximiná, and Santarém.
Zone America/Santarem -3:38:48 - LMT 1914
-4:00 Brazil -04/-03 1988 Sep 12
-4:00 - -04 2008 Jun 24 0:00
-3:00 - -03
-4:00 Brazil %z 1988 Sep 12
-4:00 - %z 2008 Jun 24 0:00
-3:00 - %z
#
# Maranhão (MA), Piauí (PI), Ceará (CE), Rio Grande do Norte (RN),
# Paraíba (PB)
Zone America/Fortaleza -2:34:00 - LMT 1914
-3:00 Brazil -03/-02 1990 Sep 17
-3:00 - -03 1999 Sep 30
-3:00 Brazil -03/-02 2000 Oct 22
-3:00 - -03 2001 Sep 13
-3:00 Brazil -03/-02 2002 Oct 1
-3:00 - -03
-3:00 Brazil %z 1990 Sep 17
-3:00 - %z 1999 Sep 30
-3:00 Brazil %z 2000 Oct 22
-3:00 - %z 2001 Sep 13
-3:00 Brazil %z 2002 Oct 1
-3:00 - %z
#
# Pernambuco (PE) (except Atlantic islands)
Zone America/Recife -2:19:36 - LMT 1914
-3:00 Brazil -03/-02 1990 Sep 17
-3:00 - -03 1999 Sep 30
-3:00 Brazil -03/-02 2000 Oct 15
-3:00 - -03 2001 Sep 13
-3:00 Brazil -03/-02 2002 Oct 1
-3:00 - -03
-3:00 Brazil %z 1990 Sep 17
-3:00 - %z 1999 Sep 30
-3:00 Brazil %z 2000 Oct 15
-3:00 - %z 2001 Sep 13
-3:00 Brazil %z 2002 Oct 1
-3:00 - %z
#
# Tocantins (TO)
Zone America/Araguaina -3:12:48 - LMT 1914
-3:00 Brazil -03/-02 1990 Sep 17
-3:00 - -03 1995 Sep 14
-3:00 Brazil -03/-02 2003 Sep 24
-3:00 - -03 2012 Oct 21
-3:00 Brazil -03/-02 2013 Sep
-3:00 - -03
-3:00 Brazil %z 1990 Sep 17
-3:00 - %z 1995 Sep 14
-3:00 Brazil %z 2003 Sep 24
-3:00 - %z 2012 Oct 21
-3:00 Brazil %z 2013 Sep
-3:00 - %z
#
# Alagoas (AL), Sergipe (SE)
Zone America/Maceio -2:22:52 - LMT 1914
-3:00 Brazil -03/-02 1990 Sep 17
-3:00 - -03 1995 Oct 13
-3:00 Brazil -03/-02 1996 Sep 4
-3:00 - -03 1999 Sep 30
-3:00 Brazil -03/-02 2000 Oct 22
-3:00 - -03 2001 Sep 13
-3:00 Brazil -03/-02 2002 Oct 1
-3:00 - -03
-3:00 Brazil %z 1990 Sep 17
-3:00 - %z 1995 Oct 13
-3:00 Brazil %z 1996 Sep 4
-3:00 - %z 1999 Sep 30
-3:00 Brazil %z 2000 Oct 22
-3:00 - %z 2001 Sep 13
-3:00 Brazil %z 2002 Oct 1
-3:00 - %z
#
# Bahia (BA)
# There are too many Salvadors elsewhere, so use America/Bahia instead
# of America/Salvador.
Zone America/Bahia -2:34:04 - LMT 1914
-3:00 Brazil -03/-02 2003 Sep 24
-3:00 - -03 2011 Oct 16
-3:00 Brazil -03/-02 2012 Oct 21
-3:00 - -03
-3:00 Brazil %z 2003 Sep 24
-3:00 - %z 2011 Oct 16
-3:00 Brazil %z 2012 Oct 21
-3:00 - %z
#
# Goiás (GO), Distrito Federal (DF), Minas Gerais (MG),
# Espírito Santo (ES), Rio de Janeiro (RJ), São Paulo (SP), Paraná (PR),
# Santa Catarina (SC), Rio Grande do Sul (RS)
Zone America/Sao_Paulo -3:06:28 - LMT 1914
-3:00 Brazil -03/-02 1963 Oct 23 0:00
-3:00 1:00 -02 1964
-3:00 Brazil -03/-02
-3:00 Brazil %z 1963 Oct 23 0:00
-3:00 1:00 %z 1964
-3:00 Brazil %z
#
# Mato Grosso do Sul (MS)
Zone America/Campo_Grande -3:38:28 - LMT 1914
-4:00 Brazil -04/-03
-4:00 Brazil %z
#
# Mato Grosso (MT)
Zone America/Cuiaba -3:44:20 - LMT 1914
-4:00 Brazil -04/-03 2003 Sep 24
-4:00 - -04 2004 Oct 1
-4:00 Brazil -04/-03
-4:00 Brazil %z 2003 Sep 24
-4:00 - %z 2004 Oct 1
-4:00 Brazil %z
#
# Rondônia (RO)
Zone America/Porto_Velho -4:15:36 - LMT 1914
-4:00 Brazil -04/-03 1988 Sep 12
-4:00 - -04
-4:00 Brazil %z 1988 Sep 12
-4:00 - %z
#
# Roraima (RR)
Zone America/Boa_Vista -4:02:40 - LMT 1914
-4:00 Brazil -04/-03 1988 Sep 12
-4:00 - -04 1999 Sep 30
-4:00 Brazil -04/-03 2000 Oct 15
-4:00 - -04
-4:00 Brazil %z 1988 Sep 12
-4:00 - %z 1999 Sep 30
-4:00 Brazil %z 2000 Oct 15
-4:00 - %z
#
# east Amazonas (AM): Boca do Acre, Jutaí, Manaus, Floriano Peixoto
# The great circle line from Tabatinga to Porto Acre divides
# east from west Amazonas.
Zone America/Manaus -4:00:04 - LMT 1914
-4:00 Brazil -04/-03 1988 Sep 12
-4:00 - -04 1993 Sep 28
-4:00 Brazil -04/-03 1994 Sep 22
-4:00 - -04
-4:00 Brazil %z 1988 Sep 12
-4:00 - %z 1993 Sep 28
-4:00 Brazil %z 1994 Sep 22
-4:00 - %z
#
# west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
# Eirunepé, Envira, Ipixuna
Zone America/Eirunepe -4:39:28 - LMT 1914
-5:00 Brazil -05/-04 1988 Sep 12
-5:00 - -05 1993 Sep 28
-5:00 Brazil -05/-04 1994 Sep 22
-5:00 - -05 2008 Jun 24 0:00
-4:00 - -04 2013 Nov 10
-5:00 - -05
-5:00 Brazil %z 1988 Sep 12
-5:00 - %z 1993 Sep 28
-5:00 Brazil %z 1994 Sep 22
-5:00 - %z 2008 Jun 24 0:00
-4:00 - %z 2013 Nov 10
-5:00 - %z
#
# Acre (AC)
Zone America/Rio_Branco -4:31:12 - LMT 1914
-5:00 Brazil -05/-04 1988 Sep 12
-5:00 - -05 2008 Jun 24 0:00
-4:00 - -04 2013 Nov 10
-5:00 - -05
-5:00 Brazil %z 1988 Sep 12
-5:00 - %z 2008 Jun 24 0:00
-4:00 - %z 2013 Nov 10
-5:00 - %z
# Chile
@@ -1382,36 +1382,36 @@ Rule Chile 2023 max - Sep Sun>=2 4:00u 1:00 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Santiago -4:42:45 - LMT 1890
-4:42:45 - SMT 1910 Jan 10 # Santiago Mean Time
-5:00 - -05 1916 Jul 1
-5:00 - %z 1916 Jul 1
-4:42:45 - SMT 1918 Sep 10
-4:00 - -04 1919 Jul 1
-4:00 - %z 1919 Jul 1
-4:42:45 - SMT 1927 Sep 1
-5:00 Chile -05/-04 1932 Sep 1
-4:00 - -04 1942 Jun 1
-5:00 - -05 1942 Aug 1
-4:00 - -04 1946 Jul 14 24:00
-4:00 1:00 -03 1946 Aug 28 24:00 # central CL
-5:00 1:00 -04 1947 Mar 31 24:00
-5:00 - -05 1947 May 21 23:00
-4:00 Chile -04/-03
-5:00 Chile %z 1932 Sep 1
-4:00 - %z 1942 Jun 1
-5:00 - %z 1942 Aug 1
-4:00 - %z 1946 Jul 14 24:00
-4:00 1:00 %z 1946 Aug 28 24:00 # central CL
-5:00 1:00 %z 1947 Mar 31 24:00
-5:00 - %z 1947 May 21 23:00
-4:00 Chile %z
Zone America/Punta_Arenas -4:43:40 - LMT 1890
-4:42:45 - SMT 1910 Jan 10
-5:00 - -05 1916 Jul 1
-5:00 - %z 1916 Jul 1
-4:42:45 - SMT 1918 Sep 10
-4:00 - -04 1919 Jul 1
-4:00 - %z 1919 Jul 1
-4:42:45 - SMT 1927 Sep 1
-5:00 Chile -05/-04 1932 Sep 1
-4:00 - -04 1942 Jun 1
-5:00 - -05 1942 Aug 1
-4:00 - -04 1946 Aug 28 24:00
-5:00 1:00 -04 1947 Mar 31 24:00
-5:00 - -05 1947 May 21 23:00
-4:00 Chile -04/-03 2016 Dec 4
-3:00 - -03
-5:00 Chile %z 1932 Sep 1
-4:00 - %z 1942 Jun 1
-5:00 - %z 1942 Aug 1
-4:00 - %z 1946 Aug 28 24:00
-5:00 1:00 %z 1947 Mar 31 24:00
-5:00 - %z 1947 May 21 23:00
-4:00 Chile %z 2016 Dec 4
-3:00 - %z
Zone Pacific/Easter -7:17:28 - LMT 1890
-7:17:28 - EMT 1932 Sep # Easter Mean Time
-7:00 Chile -07/-06 1982 Mar 14 3:00u # Easter Time
-6:00 Chile -06/-05
-7:00 Chile %z 1982 Mar 14 3:00u # Easter Time
-6:00 Chile %z
#
# Salas y Gómez Island is uninhabited.
# Other Chilean locations, including Juan Fernández Is, Desventuradas Is,
@@ -1431,10 +1431,10 @@ Zone Pacific/Easter -7:17:28 - LMT 1890
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Palmer 0 - -00 1965
-4:00 Arg -04/-03 1969 Oct 5
-3:00 Arg -03/-02 1982 May
-4:00 Chile -04/-03 2016 Dec 4
-3:00 - -03
-4:00 Arg %z 1969 Oct 5
-3:00 Arg %z 1982 May
-4:00 Chile %z 2016 Dec 4
-3:00 - %z
# Colombia
@@ -1453,7 +1453,7 @@ Rule CO 1993 only - Feb 6 24:00 0 -
#STDOFF -4:56:16.4
Zone America/Bogota -4:56:16 - LMT 1884 Mar 13
-4:56:16 - BMT 1914 Nov 23 # Bogotá Mean Time
-5:00 CO -05/-04
-5:00 CO %z
# Malpelo, Providencia, San Andres
# no information; probably like America/Bogota
@@ -1484,10 +1484,10 @@ Rule Ecuador 1993 only - Feb 5 0:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Guayaquil -5:19:20 - LMT 1890
-5:14:00 - QMT 1931 # Quito Mean Time
-5:00 Ecuador -05/-04
-5:00 Ecuador %z
Zone Pacific/Galapagos -5:58:24 - LMT 1931 # Puerto Baquerizo Moreno
-5:00 - -05 1986
-6:00 Ecuador -06/-05
-5:00 - %z 1986
-6:00 Ecuador %z
# Falklands
@@ -1587,10 +1587,10 @@ Rule Falk 2001 2010 - Sep Sun>=1 2:00 1:00 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Atlantic/Stanley -3:51:24 - LMT 1890
-3:51:24 - SMT 1912 Mar 12 # Stanley Mean Time
-4:00 Falk -04/-03 1983 May
-3:00 Falk -03/-02 1985 Sep 15
-4:00 Falk -04/-03 2010 Sep 5 2:00
-3:00 - -03
-4:00 Falk %z 1983 May
-3:00 Falk %z 1985 Sep 15
-4:00 Falk %z 2010 Sep 5 2:00
-3:00 - %z
# French Guiana
# For the 1911/1912 establishment of standard time in French possessions, see:
@@ -1598,8 +1598,8 @@ Zone Atlantic/Stanley -3:51:24 - LMT 1890
# page 752, 18b.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1
-4:00 - -04 1967 Oct
-3:00 - -03
-4:00 - %z 1967 Oct
-3:00 - %z
# Guyana
@@ -1633,10 +1633,10 @@ Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Guyana -3:52:39 - LMT 1911 Aug 1 # Georgetown
-4:00 - -04 1915 Mar 1
-3:45 - -0345 1975 Aug 1
-3:00 - -03 1992 Mar 29 1:00
-4:00 - -04
-4:00 - %z 1915 Mar 1
-3:45 - %z 1975 Aug 1
-3:00 - %z 1992 Mar 29 1:00
-4:00 - %z
# Paraguay
#
@@ -1734,9 +1734,9 @@ Rule Para 2013 max - Mar Sun>=22 0:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Asuncion -3:50:40 - LMT 1890
-3:50:40 - AMT 1931 Oct 10 # Asunción Mean Time
-4:00 - -04 1972 Oct
-3:00 - -03 1974 Apr
-4:00 Para -04/-03
-4:00 - %z 1972 Oct
-3:00 - %z 1974 Apr
-4:00 Para %z
# Peru
#
@@ -1763,12 +1763,12 @@ Rule Peru 1994 only - Apr 1 0:00 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Lima -5:08:12 - LMT 1890
-5:08:36 - LMT 1908 Jul 28 # Lima Mean Time?
-5:00 Peru -05/-04
-5:00 Peru %z
# South Georgia
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Atlantic/South_Georgia -2:26:08 - LMT 1890 # Grytviken
-2:00 - -02
-2:00 - %z
# South Sandwich Is
# uninhabited; scientific personnel have wintered
@@ -1778,8 +1778,8 @@ Zone Atlantic/South_Georgia -2:26:08 - LMT 1890 # Grytviken
Zone America/Paramaribo -3:40:40 - LMT 1911
-3:40:52 - PMT 1935 # Paramaribo Mean Time
-3:40:36 - PMT 1945 Oct # The capital moved?
-3:30 - -0330 1984 Oct
-3:00 - -03
-3:30 - %z 1984 Oct
-3:00 - %z
# Uruguay
# From Paul Eggert (1993-11-18):
@@ -1994,15 +1994,15 @@ Rule Uruguay 2006 2014 - Oct Sun>=1 2:00 1:00 -
# This Zone can be simplified once we assume zic %z.
Zone America/Montevideo -3:44:51 - LMT 1908 Jun 10
-3:44:51 - MMT 1920 May 1 # Montevideo MT
-4:00 - -04 1923 Oct 1
-3:30 Uruguay -0330/-03 1942 Dec 14
-3:00 Uruguay -03/-0230 1960
-3:00 Uruguay -03/-02 1968
-3:00 Uruguay -03/-0230 1970
-3:00 Uruguay -03/-02 1974
-3:00 Uruguay -03/-0130 1974 Mar 10
-3:00 Uruguay -03/-0230 1974 Dec 22
-3:00 Uruguay -03/-02
-4:00 - %z 1923 Oct 1
-3:30 Uruguay %z 1942 Dec 14
-3:00 Uruguay %z 1960
-3:00 Uruguay %z 1968
-3:00 Uruguay %z 1970
-3:00 Uruguay %z 1974
-3:00 Uruguay %z 1974 Mar 10
-3:00 Uruguay %z 1974 Dec 22
-3:00 Uruguay %z
# Venezuela
#
@@ -2036,7 +2036,7 @@ Zone America/Montevideo -3:44:51 - LMT 1908 Jun 10
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Caracas -4:27:44 - LMT 1890
-4:27:40 - CMT 1912 Feb 12 # Caracas Mean Time?
-4:30 - -0430 1965 Jan 1 0:00
-4:00 - -04 2007 Dec 9 3:00
-4:30 - -0430 2016 May 1 2:30
-4:00 - -04
-4:30 - %z 1965 Jan 1 0:00
-4:00 - %z 2007 Dec 9 3:00
-4:30 - %z 2016 May 1 2:30
-4:00 - %z

View File

@@ -287,8 +287,7 @@ MK +4159+02126 Europe/Skopje
ML +1239-00800 Africa/Bamako
MM +1647+09610 Asia/Yangon
MN +4755+10653 Asia/Ulaanbaatar most of Mongolia
MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan
MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar
MN +4801+09139 Asia/Hovd Bayan-Olgii, Hovd, Uvs
MO +221150+1133230 Asia/Macau
MP +1512+14545 Pacific/Saipan
MQ +1436-06105 America/Martinique

View File

@@ -67,10 +67,12 @@ JVM_CFLAGS_TARGET_DEFINES += \
#
ifeq ($(DEBUG_LEVEL), release)
# release builds disable uses of assert macro from <assert.h>.
JVM_CFLAGS_DEBUGLEVEL := -DNDEBUG
# For hotspot, release builds differ internally between "optimized" and "product"
# in that "optimize" does not define PRODUCT.
ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized)
JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT
JVM_CFLAGS_DEBUGLEVEL += -DPRODUCT
endif
else ifeq ($(DEBUG_LEVEL), fastdebug)
JVM_CFLAGS_DEBUGLEVEL := -DASSERT

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024, 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
@@ -273,7 +273,7 @@ public final class TzdbZoneRulesCompiler {
// link version-region-rules
out.writeShort(builtZones.size());
for (Map.Entry<String, ZoneRules> entry : builtZones.entrySet()) {
int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
int regionIndex = findRegionIndex(regionArray, entry.getKey());
int rulesIndex = rulesList.indexOf(entry.getValue());
out.writeShort(regionIndex);
out.writeShort(rulesIndex);
@@ -281,8 +281,8 @@ public final class TzdbZoneRulesCompiler {
// alias-region
out.writeShort(links.size());
for (Map.Entry<String, String> entry : links.entrySet()) {
int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
int aliasIndex = findRegionIndex(regionArray, entry.getKey());
int regionIndex = findRegionIndex(regionArray, entry.getValue());
out.writeShort(aliasIndex);
out.writeShort(regionIndex);
}
@@ -294,6 +294,14 @@ public final class TzdbZoneRulesCompiler {
}
}
private static int findRegionIndex(String[] regionArray, String region) {
int index = Arrays.binarySearch(regionArray, region);
if (index < 0) {
throw new IllegalArgumentException("Unknown region: " + region);
}
return index;
}
/** Whether to output verbose messages. */
private boolean verbose;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2024, 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
@@ -163,7 +163,8 @@ class TzdbZoneRulesProvider {
}
continue;
}
if (line.startsWith("Zone")) { // parse Zone line
int token0len = tokens.length > 0 ? tokens[0].length() : line.length();
if (line.regionMatches(true, 0, "Zone", 0, token0len)) { // parse Zone line
String name = tokens[1];
if (excludedZones.contains(name)){
continue;
@@ -181,13 +182,13 @@ class TzdbZoneRulesProvider {
if (zLine.parse(tokens, 2)) {
openZone = null;
}
} else if (line.startsWith("Rule")) { // parse Rule line
} else if (line.regionMatches(true, 0, "Rule", 0, token0len)) { // parse Rule line
String name = tokens[1];
if (!rules.containsKey(name)) {
rules.put(name, new ArrayList<RuleLine>(10));
}
rules.get(name).add(new RuleLine().parse(tokens));
} else if (line.startsWith("Link")) { // parse link line
} else if (line.regionMatches(true, 0, "Link", 0, token0len)) { // parse link line
if (tokens.length >= 3) {
String realId = tokens[1];
String aliasId = tokens[2];
@@ -303,7 +304,7 @@ class TzdbZoneRulesProvider {
month = parseMonth(tokens[off++]);
if (off < tokens.length) {
String dayRule = tokens[off++];
if (dayRule.startsWith("last")) {
if (dayRule.regionMatches(true, 0, "last", 0, 4)) {
dayOfMonth = -1;
dayOfWeek = parseDayOfWeek(dayRule.substring(4));
adjustForwards = false;
@@ -354,42 +355,45 @@ class TzdbZoneRulesProvider {
}
int parseYear(String year, int defaultYear) {
switch (year.toLowerCase()) {
case "min": return 1900;
case "max": return Year.MAX_VALUE;
case "only": return defaultYear;
}
int len = year.length();
if (year.regionMatches(true, 0, "minimum", 0, len)) return 1900;
if (year.regionMatches(true, 0, "maximum", 0, len)) return Year.MAX_VALUE;
if (year.regionMatches(true, 0, "only", 0, len)) return defaultYear;
return Integer.parseInt(year);
}
Month parseMonth(String mon) {
switch (mon) {
case "Jan": return Month.JANUARY;
case "Feb": return Month.FEBRUARY;
case "Mar": return Month.MARCH;
case "Apr": return Month.APRIL;
case "May": return Month.MAY;
case "Jun": return Month.JUNE;
case "Jul": return Month.JULY;
case "Aug": return Month.AUGUST;
case "Sep": return Month.SEPTEMBER;
case "Oct": return Month.OCTOBER;
case "Nov": return Month.NOVEMBER;
case "Dec": return Month.DECEMBER;
}
int len = mon.length();
if (mon.regionMatches(true, 0, "January", 0, len)) return Month.JANUARY;
if (mon.regionMatches(true, 0, "February", 0, len)) return Month.FEBRUARY;
if (mon.regionMatches(true, 0, "March", 0, len)) return Month.MARCH;
if (mon.regionMatches(true, 0, "April", 0, len)) return Month.APRIL;
if (mon.regionMatches(true, 0, "May", 0, len)) return Month.MAY;
if (mon.regionMatches(true, 0, "June", 0, len)) return Month.JUNE;
if (mon.regionMatches(true, 0, "July", 0, len)) return Month.JULY;
if (mon.regionMatches(true, 0, "August", 0, len)) return Month.AUGUST;
if (mon.regionMatches(true, 0, "September", 0, len)) return Month.SEPTEMBER;
if (mon.regionMatches(true, 0, "October", 0, len)) return Month.OCTOBER;
if (mon.regionMatches(true, 0, "November", 0, len)) return Month.NOVEMBER;
if (mon.regionMatches(true, 0, "December", 0, len)) return Month.DECEMBER;
throw new IllegalArgumentException("Unknown month: " + mon);
}
DayOfWeek parseDayOfWeek(String dow) {
switch (dow) {
case "Mon": return DayOfWeek.MONDAY;
case "Tue": return DayOfWeek.TUESDAY;
case "Wed": return DayOfWeek.WEDNESDAY;
case "Thu": return DayOfWeek.THURSDAY;
case "Fri": return DayOfWeek.FRIDAY;
case "Sat": return DayOfWeek.SATURDAY;
case "Sun": return DayOfWeek.SUNDAY;
}
int len = dow.length();
if (dow.regionMatches(true, 0, "Monday", 0, len)) return DayOfWeek.MONDAY;
if (dow.regionMatches(true, 0, "Tuesday", 0, len)) return DayOfWeek.TUESDAY;
if (dow.regionMatches(true, 0, "Wednesday", 0, len)) return DayOfWeek.WEDNESDAY;
if (dow.regionMatches(true, 0, "Thursday", 0, len)) return DayOfWeek.THURSDAY;
if (dow.regionMatches(true, 0, "Friday", 0, len)) return DayOfWeek.FRIDAY;
if (dow.regionMatches(true, 0, "Saturday", 0, len)) return DayOfWeek.SATURDAY;
if (dow.regionMatches(true, 0, "Sunday", 0, len)) return DayOfWeek.SUNDAY;
throw new IllegalArgumentException("Unknown day-of-week: " + dow);
}

View File

@@ -1046,10 +1046,11 @@ class CodeString: public CHeapObj<mtCode> {
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);
}
@@ -1057,7 +1058,7 @@ class CodeString: public CHeapObj<mtCode> {
public:
CodeString(const char * string, intptr_t offset = -1)
: _next(NULL), _offset(offset) {
: _next(NULL), _prev(NULL), _offset(offset) {
_string = os::strdup(string, mtCode);
}
@@ -1065,7 +1066,12 @@ class CodeString: public CHeapObj<mtCode> {
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()) {
@@ -1093,12 +1099,9 @@ CodeString* CodeStrings::find(intptr_t offset) const {
// 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;
}
@@ -1117,12 +1120,16 @@ void CodeStrings::add_comment(intptr_t offset, const char * comment) {
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
@@ -1138,8 +1145,11 @@ void CodeStrings::copy(CodeStrings& other) {
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();
}
@@ -1168,6 +1178,10 @@ void CodeStrings::free() {
// 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;
}
@@ -1178,6 +1192,9 @@ const char* CodeStrings::add_string(const char * string) {
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();

View File

@@ -249,6 +249,7 @@ class CodeStrings {
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 @@ private:
void set_null_and_invalidate() {
#ifndef PRODUCT
_strings = NULL;
_strings_last = NULL;
#ifdef ASSERT
_defunct = true;
#endif
@@ -272,6 +274,7 @@ public:
CodeStrings() {
#ifndef PRODUCT
_strings = NULL;
_strings_last = NULL;
#ifdef ASSERT
_defunct = false;
#endif

View File

@@ -1320,7 +1320,7 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) {
const TypeInt* init_t = phase->type(in(Init) )->is_int();
const TypeInt* limit_t = phase->type(in(Limit))->is_int();
int stride_p;
jlong stride_p;
jlong lim, ini;
julong max;
if (stride_con > 0) {
@@ -1329,10 +1329,10 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) {
ini = init_t->_lo;
max = (julong)max_jint;
} else {
stride_p = -stride_con;
stride_p = -(jlong)stride_con;
lim = init_t->_hi;
ini = limit_t->_lo;
max = (julong)min_jint;
max = (julong)(juint)min_jint; // double cast to get 0x0000000080000000, not 0xffffffff80000000
}
julong range = lim - ini + stride_p;
if (range <= max) {

View File

@@ -3561,6 +3561,10 @@ int SWPointer::Tracer::_depth = 0;
SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool analyze_only) :
_mem(mem), _slp(slp), _base(NULL), _adr(NULL),
_scale(0), _offset(0), _invar(NULL), _negate_invar(false),
_has_int_index_after_convI2L(false),
_int_index_after_convI2L_offset(0),
_int_index_after_convI2L_invar(NULL),
_int_index_after_convI2L_scale(0),
_nstack(nstack), _analyze_only(analyze_only),
_stack_idx(0)
#ifndef PRODUCT
@@ -3619,6 +3623,11 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool anal
NOT_PRODUCT(if(_slp->is_trace_alignment()) _tracer.restore_depth();)
NOT_PRODUCT(_tracer.ctor_6(mem);)
if (!is_safe_to_use_as_simple_form(base, adr)) {
assert(!valid(), "does not have simple form");
return;
}
_base = base;
_adr = adr;
assert(valid(), "Usable");
@@ -3629,6 +3638,10 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool anal
SWPointer::SWPointer(SWPointer* p) :
_mem(p->_mem), _slp(p->_slp), _base(NULL), _adr(NULL),
_scale(0), _offset(0), _invar(NULL), _negate_invar(false),
_has_int_index_after_convI2L(false),
_int_index_after_convI2L_offset(0),
_int_index_after_convI2L_invar(NULL),
_int_index_after_convI2L_scale(0),
_nstack(p->_nstack), _analyze_only(p->_analyze_only),
_stack_idx(p->_stack_idx)
#ifndef PRODUCT
@@ -3636,6 +3649,354 @@ SWPointer::SWPointer(SWPointer* p) :
#endif
{}
// We would like to make decisions about aliasing (i.e. removing memory edges) and adjacency
// (i.e. which loads/stores can be packed) based on the simple form:
//
// s_pointer = adr + offset + invar + scale * ConvI2L(iv)
//
// However, we parse the compound-long-int form:
//
// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index)
// int_index = int_offset + int_invar + int_scale * iv
//
// In general, the simple and the compound-long-int form do not always compute the same pointer
// at runtime. For example, the simple form would give a different result due to an overflow
// in the int_index.
//
// Example:
// For both forms, we have:
// iv = 0
// scale = 1
//
// We now account the offset and invar once to the long part and once to the int part:
// Pointer 1 (long offset and long invar):
// long_offset = min_int
// long_invar = min_int
// int_offset = 0
// int_invar = 0
//
// Pointer 2 (int offset and int invar):
// long_offset = 0
// long_invar = 0
// int_offset = min_int
// int_invar = min_int
//
// This gives us the following pointers:
// Compound-long-int form pointers:
// Form:
// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + int_invar + int_scale * iv)
//
// Pointers:
// c_pointer1 = adr + min_int + min_int + 1 * ConvI2L(0 + 0 + 1 * 0)
// = adr + min_int + min_int
// = adr - 2^32
//
// c_pointer2 = adr + 0 + 0 + 1 * ConvI2L(min_int + min_int + 1 * 0)
// = adr + ConvI2L(min_int + min_int)
// = adr + 0
// = adr
//
// Simple form pointers:
// Form:
// s_pointer = adr + offset + invar + scale * ConvI2L(iv)
// s_pointer = adr + (long_offset + int_offset) + (long_invar + int_invar) + (long_scale * int_scale) * ConvI2L(iv)
//
// Pointers:
// s_pointer1 = adr + (min_int + 0 ) + (min_int + 0 ) + 1 * 0
// = adr + min_int + min_int
// = adr - 2^32
// s_pointer2 = adr + (0 + min_int ) + (0 + min_int ) + 1 * 0
// = adr + min_int + min_int
// = adr - 2^32
//
// We see that the two addresses are actually 2^32 bytes apart (derived from the c_pointers), but their simple form look identical.
//
// Hence, we need to determine in which cases it is safe to make decisions based on the simple
// form, rather than the compound-long-int form. If we cannot prove that using the simple form
// is safe (i.e. equivalent to the compound-long-int form), then we do not get a valid SWPointer,
// and the associated memop cannot be vectorized.
bool SWPointer::is_safe_to_use_as_simple_form(Node* base, Node* adr) const {
#ifndef _LP64
// On 32-bit platforms, there is never an explicit int_index with ConvI2L for the iv. Thus, the
// parsed pointer form is always the simple form, with int operations:
//
// pointer = adr + offset + invar + scale * iv
//
assert(!_has_int_index_after_convI2L, "32-bit never has an int_index with ConvI2L for the iv");
return true;
#else
// Array accesses that are not Unsafe always have a RangeCheck which ensures that there is no
// int_index overflow. This implies that the conversion to long can be done separately:
//
// ConvI2L(int_index) = ConvI2L(int_offset) + ConvI2L(int_invar) + ConvI2L(scale) * ConvI2L(iv)
//
// And hence, the simple form is guaranteed to be identical to the compound-long-int form at
// runtime and the SWPointer is safe/valid to be used.
const TypeAryPtr* ary_ptr_t = _mem->adr_type()->isa_aryptr();
if (ary_ptr_t != NULL) {
if (!_mem->is_unsafe_access()) {
return true;
}
}
// We did not find the int_index. Just to be safe, reject this SWPointer.
if (!_has_int_index_after_convI2L) {
return false;
}
int int_offset = _int_index_after_convI2L_offset;
Node* int_invar = _int_index_after_convI2L_invar;
int int_scale = _int_index_after_convI2L_scale;
int long_scale = _scale / int_scale;
// If "int_index = iv", then the simple form is identical to the compound-long-int form.
//
// int_index = int_offset + int_invar + int_scale * iv
// = 0 0 1 * iv
// = iv
if (int_offset == 0 && int_invar == NULL && int_scale == 1) {
return true;
}
// Intuition: What happens if the int_index overflows? Let us look at two pointers on the "overflow edge":
//
// pointer1 = adr + ConvI2L(int_index1)
// pointer2 = adr + ConvI2L(int_index2)
//
// int_index1 = max_int + 0 = max_int -> very close to but before the overflow
// int_index2 = max_int + 1 = min_int -> just enough to get the overflow
//
// When looking at the difference of pointer1 and pointer2, we notice that it is very large
// (almost 2^32). Since arrays have at most 2^31 elements, chances are high that pointer2 is
// an actual out-of-bounds access at runtime. These would normally be prevented by range checks
// at runtime. However, if the access was done by using Unsafe, where range checks are omitted,
// then an out-of-bounds access constitutes undefined behavior. This means that we are allowed to
// do anything, including changing the behavior.
//
// If we can set the right conditions, we have a guarantee that an overflow is either impossible
// (no overflow or range checks preventing that) or undefined behavior. In both cases, we are
// safe to do a vectorization.
//
// Approach: We want to prove a lower bound for the distance between these two pointers, and an
// upper bound for the size of a memory object. We can derive such an upper bound for
// arrays. We know they have at most 2^31 elements. If we know the size of the elements
// in bytes, we have:
//
// array_element_size_in_bytes * 2^31 >= max_possible_array_size_in_bytes
// >= array_size_in_bytes (ARR)
//
// If some small difference "delta" leads to an int_index overflow, we know that the
// int_index1 before overflow must have been close to max_int, and the int_index2 after
// the overflow must be close to min_int:
//
// pointer1 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index1)
// =approx adr + long_offset + long_invar + long_scale * max_int
//
// pointer2 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index2)
// =approx adr + long_offset + long_invar + long_scale * min_int
//
// We realize that the pointer difference is very large:
//
// difference =approx long_scale * 2^32
//
// Hence, if we set the right condition for long_scale and array_element_size_in_bytes,
// we can prove that an overflow is impossible (or would imply undefined behaviour).
//
// We must now take this intuition, and develop a rigorous proof. We start by stating the problem
// more precisely, with the help of some definitions and the Statement we are going to prove.
//
// Definition:
// Two SWPointers are "comparable" (i.e. SWPointer::comparable is true, set with SWPointer::cmp()),
// iff all of these conditions apply for the simple form:
// 1) Both SWPointers are valid.
// 2) The adr are identical, or both are array bases of different arrays.
// 3) They have identical scale.
// 4) They have identical invar.
// 5) The difference in offsets is limited: abs(offset1 - offset2) < 2^31. (DIFF)
//
// For the Vectorization Optimization, we pair-wise compare SWPointers and determine if they are:
// 1) "not comparable":
// We do not optimize them (assume they alias, not assume adjacency).
//
// Whenever we chose this option based on the simple form, it is also correct based on the
// compound-long-int form, since we make no optimizations based on it.
//
// 2) "comparable" with different array bases at runtime:
// We assume they do not alias (remove memory edges), but not assume adjacency.
//
// Whenever we have two different array bases for the simple form, we also have different
// array bases for the compound-long-form. Since SWPointers provably point to different
// memory objects, they can never alias.
//
// 3) "comparable" with the same base address:
// We compute the relative pointer difference, and based on the load/store size we can
// compute aliasing and adjacency.
//
// We must find a condition under which the pointer difference of the simple form is
// identical to the pointer difference of the compound-long-form. We do this with the
// Statement below, which we then proceed to prove.
//
// Statement:
// If two SWPointers satisfy these 3 conditions:
// 1) They are "comparable".
// 2) They have the same base address.
// 3) Their long_scale is a multiple of the array element size in bytes:
//
// abs(long_scale) % array_element_size_in_bytes = 0 (A)
//
// Then their pointer difference of the simple form is identical to the pointer difference
// of the compound-long-int form.
//
// More precisely:
// Such two SWPointers by definition have identical adr, invar, and scale.
// Their simple form is:
//
// s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) (B1)
// s_pointer2 = adr + offset2 + invar + scale * ConvI2L(iv) (B2)
//
// Thus, the pointer difference of the simple forms collapses to the difference in offsets:
//
// s_difference = s_pointer1 - s_pointer2 = offset1 - offset2 (C)
//
// Their compound-long-int form for these SWPointer is:
//
// c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) (D1)
// int_index1 = int_offset1 + int_invar1 + int_scale1 * iv (D2)
//
// c_pointer2 = adr + long_offset2 + long_invar2 + long_scale2 * ConvI2L(int_index2) (D3)
// int_index2 = int_offset2 + int_invar2 + int_scale2 * iv (D4)
//
// And these are the offset1, offset2, invar and scale from the simple form (B1) and (B2):
//
// offset1 = long_offset1 + long_scale1 * ConvI2L(int_offset1) (D5)
// offset2 = long_offset2 + long_scale2 * ConvI2L(int_offset2) (D6)
//
// invar = long_invar1 + long_scale1 * ConvI2L(int_invar1)
// = long_invar2 + long_scale2 * ConvI2L(int_invar2) (D7)
//
// scale = long_scale1 * ConvI2L(int_scale1)
// = long_scale2 * ConvI2L(int_scale2) (D8)
//
// The pointer difference of the compound-long-int form is defined as:
//
// c_difference = c_pointer1 - c_pointer2
//
// Thus, the statement claims that for the two SWPointer we have:
//
// s_difference = c_difference (Statement)
//
// We prove the Statement with the help of a Lemma:
//
// Lemma:
// There is some integer x, such that:
//
// c_difference = s_difference + array_element_size_in_bytes * x * 2^32 (Lemma)
//
// From condition (DIFF), we can derive:
//
// abs(s_difference) < 2^31 (E)
//
// Assuming the Lemma, we prove the Statement:
// If "x = 0" (intuitively: the int_index does not overflow), then:
// c_difference = s_difference
// and hence the simple form computes the same pointer difference as the compound-long-int form.
// If "x != 0" (intuitively: the int_index overflows), then:
// abs(c_difference) >= abs(s_difference + array_element_size_in_bytes * x * 2^32)
// >= array_element_size_in_bytes * 2^32 - abs(s_difference)
// -- apply (E) --
// > array_element_size_in_bytes * 2^32 - 2^31
// >= array_element_size_in_bytes * 2^31
// -- apply (ARR) --
// >= max_possible_array_size_in_bytes
// >= array_size_in_bytes
//
// This shows that c_pointer1 and c_pointer2 have a distance that exceeds the maximum array size.
// Thus, at least one of the two pointers must be outside of the array bounds. But we can assume
// that out-of-bounds accesses do not happen. If they still do, it is undefined behavior. Hence,
// we are allowed to do anything. We can also "safely" use the simple form in this case even though
// it might not match the compound-long-int form at runtime.
// QED Statement.
//
// We must now prove the Lemma.
//
// ConvI2L always truncates by some power of 2^32, i.e. there is some integer y such that:
//
// ConvI2L(y1 + y2) = ConvI2L(y1) + ConvI2L(y2) + 2^32 * y (F)
//
// It follows, that there is an integer y1 such that:
//
// ConvI2L(int_index1) = ConvI2L(int_offset1 + int_invar1 + int_scale1 * iv)
// -- apply (F) --
// = ConvI2L(int_offset1)
// + ConvI2L(int_invar1)
// + ConvI2L(int_scale1) * ConvI2L(iv)
// + y1 * 2^32 (G)
//
// Thus, we can write the compound-long-int form (D1) as:
//
// c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1)
// -- apply (G) --
// = adr
// + long_offset1
// + long_invar1
// + long_scale1 * ConvI2L(int_offset1)
// + long_scale1 * ConvI2L(int_invar1)
// + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv)
// + long_scale1 * y1 * 2^32 (H)
//
// And we can write the simple form as:
//
// s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv)
// -- apply (D5, D7, D8) --
// = adr
// + long_offset1
// + long_scale1 * ConvI2L(int_offset1)
// + long_invar1
// + long_scale1 * ConvI2L(int_invar1)
// + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) (K)
//
// We now compute the pointer difference between the simple (K) and compound-long-int form (H).
// Most terms cancel out immediately:
//
// sc_difference1 = c_pointer1 - s_pointer1 = long_scale1 * y1 * 2^32 (L)
//
// Rearranging the equation (L), we get:
//
// c_pointer1 = s_pointer1 + long_scale1 * y1 * 2^32 (M)
//
// And since long_scale1 is a multiple of array_element_size_in_bytes, there is some integer
// x1, such that (M) implies:
//
// c_pointer1 = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 (N)
//
// With an analogue equation for c_pointer2, we can now compute the pointer difference for
// the compound-long-int form:
//
// c_difference = c_pointer1 - c_pointer2
// -- apply (N) --
// = s_pointer1 + array_element_size_in_bytes * x1 * 2^32
// -(s_pointer2 + array_element_size_in_bytes * x2 * 2^32)
// -- where "x = x1 - x2" --
// = s_pointer1 - s_pointer2 + array_element_size_in_bytes * x * 2^32
// -- apply (C) --
// = s_difference + array_element_size_in_bytes * x * 2^32
// QED Lemma.
if (ary_ptr_t != NULL) {
BasicType array_element_bt = ary_ptr_t->elem()->array_element_basic_type();
if (is_java_primitive(array_element_bt)) {
int array_element_size_in_bytes = type2aelembytes(array_element_bt);
if (abs(long_scale) % array_element_size_in_bytes == 0) {
return true;
}
}
}
// General case: we do not know if it is safe to use the simple form.
return false;
#endif
}
bool SWPointer::is_main_loop_member(Node* n) const {
Node* n_c = phase()->get_ctrl(n);
return lpt()->is_member(phase()->get_loop(n_c));
@@ -3685,11 +4046,41 @@ bool SWPointer::scaled_iv_plus_offset(Node* n) {
}
} else if (opc == Op_SubI) {
if (offset_plus_k(n->in(2), true) && scaled_iv_plus_offset(n->in(1))) {
// (offset1 + invar1 + scale * iv) - (offset2) or
// (offset1 + scale * iv) - (offset2 + invar1)
// Subtraction handled via "negate" flag of "offset_plus_k".
NOT_PRODUCT(_tracer.scaled_iv_plus_offset_6(n);)
return true;
}
if (offset_plus_k(n->in(1)) && scaled_iv_plus_offset(n->in(2))) {
_scale *= -1;
SWPointer tmp(this);
if (offset_plus_k(n->in(1)) && tmp.scaled_iv_plus_offset(n->in(2))) {
// (offset1 + invar1) - (offset2 + scale * iv) or
// (offset1) - (offset2 + invar1 + scale * iv)
// Subtraction handled explicitly below.
assert(_scale == 0, "shouldn't be set yet");
// _scale = -tmp._scale
if (!try_MulI_no_overflow(-1, tmp._scale, _scale)) {
return false; // mul overflow.
}
// _offset -= tmp._offset
if (!try_SubI_no_overflow(_offset, tmp._offset, _offset)) {
return false; // sub overflow.
}
// _invar -= tmp._invar
if (tmp._invar != NULL) {
if (_invar != NULL) {
return false;
}
_invar = tmp._invar;
_negate_invar = !tmp._negate_invar;
}
// SWPointer tmp does not have an integer part to be forwarded
// (tmp._has_int_index_after_convI2L is false) because n is a SubI, all
// nodes above must also be of integer type (ConvL2I is not handled
// to allow a long) and ConvI2L (the only node that can add an integer
// part) won't be present.
NOT_PRODUCT(_tracer.scaled_iv_plus_offset_7(n);)
return true;
}
@@ -3732,17 +4123,59 @@ bool SWPointer::scaled_iv(Node* n) {
}
} else if (opc == Op_LShiftI) {
if (n->in(1) == iv() && n->in(2)->is_Con()) {
_scale = 1 << n->in(2)->get_int();
if (!try_LShiftI_no_overflow(1, n->in(2)->get_int(), _scale)) {
return false; // shift overflow.
}
NOT_PRODUCT(_tracer.scaled_iv_6(n, _scale);)
return true;
}
} else if (opc == Op_ConvI2L) {
} else if (opc == Op_ConvI2L && !has_iv()) {
if (n->in(1)->Opcode() == Op_CastII &&
n->in(1)->as_CastII()->has_range_check()) {
// Skip range check dependent CastII nodes
n = n->in(1);
}
if (scaled_iv_plus_offset(n->in(1))) {
// So far we have not found the iv yet, and are about to enter a ConvI2L subgraph,
// which may be the int index (that might overflow) for the memory access, of the form:
//
// int_index = int_offset + int_invar + int_scale * iv
//
// If we simply continue parsing with the current SWPointer, then the int_offset and
// int_invar simply get added to the long offset and invar. But for the checks in
// SWPointer::is_safe_to_use_as_simple_form() we need to have explicit access to the
// int_index. Thus, we must parse it explicitly here. For this, we use a temporary
// SWPointer, to pattern match the int_index sub-expression of the address.
NOT_PRODUCT(Tracer::Depth dddd;)
SWPointer tmp(this);
NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);)
if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) {
// We successfully matched an integer index, of the form:
// int_index = int_offset + int_invar + int_scale * iv
// Forward scale.
assert(_scale == 0 && tmp._scale != 0, "iv only found just now");
_scale = tmp._scale;
// Accumulate offset.
if (!try_AddI_no_overflow(_offset, tmp._offset, _offset)) {
return false; // add overflow.
}
// Forward invariant if not already found.
if (tmp._invar != NULL) {
if (_invar != NULL) {
return false;
}
_invar = tmp._invar;
_negate_invar = tmp._negate_invar;
}
// Set info about the int_index:
assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
_has_int_index_after_convI2L = true;
_int_index_after_convI2L_offset = tmp._offset;
_int_index_after_convI2L_invar = tmp._invar;
_int_index_after_convI2L_scale = tmp._scale;
NOT_PRODUCT(_tracer.scaled_iv_7(n);)
return true;
}
@@ -3757,11 +4190,30 @@ bool SWPointer::scaled_iv(Node* n) {
if (tmp.scaled_iv_plus_offset(n->in(1))) {
if (tmp._invar == NULL || _slp->do_vector_loop()) {
int mult = 1 << n->in(2)->get_int();
_scale = tmp._scale * mult;
_offset += tmp._offset * mult;
int shift = (int)(n->in(2)->get_int());
// Accumulate scale.
if (!try_LShiftI_no_overflow(tmp._scale, shift, _scale)) {
return false; // shift overflow.
}
// Accumulate offset.
jint shifted_offset = 0;
if (!try_LShiftI_no_overflow(tmp._offset, shift, shifted_offset)) {
return false; // shift overflow.
}
if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) {
return false; // add overflow.
}
// Accumulate invar.
_invar = tmp._invar;
NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, mult);)
// Forward info about the int_index:
assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
_has_int_index_after_convI2L = tmp._has_int_index_after_convI2L;
_int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset;
_int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar;
_int_index_after_convI2L_scale = tmp._int_index_after_convI2L_scale;
NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, 1 << shift);)
return true;
}
}
@@ -3780,7 +4232,9 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) {
int opc = n->Opcode();
if (opc == Op_ConI) {
_offset += negate ? -(n->get_int()) : n->get_int();
if (!try_AddSubI_no_overflow(_offset, n->get_int(), negate, _offset)) {
return false; // add/sub overflow.
}
NOT_PRODUCT(_tracer.offset_plus_k_2(n, _offset);)
return true;
} else if (opc == Op_ConL) {
@@ -3789,7 +4243,9 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) {
if (t->higher_equal(TypeLong::INT)) {
jlong loff = n->get_long();
jint off = (jint)loff;
_offset += negate ? -off : loff;
if (!try_AddSubI_no_overflow(_offset, off, negate, _offset)) {
return false; // add/sub overflow.
}
NOT_PRODUCT(_tracer.offset_plus_k_3(n, _offset);)
return true;
}
@@ -3808,11 +4264,15 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) {
if (n->in(2)->is_Con() && invariant(n->in(1))) {
_negate_invar = negate;
_invar = n->in(1);
_offset += negate ? -(n->in(2)->get_int()) : n->in(2)->get_int();
if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), negate, _offset)) {
return false; // add/sub overflow.
}
NOT_PRODUCT(_tracer.offset_plus_k_6(n, _invar, _negate_invar, _offset);)
return true;
} else if (n->in(1)->is_Con() && invariant(n->in(2))) {
_offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int();
if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) {
return false; // add/sub overflow.
}
_negate_invar = negate;
_invar = n->in(2);
NOT_PRODUCT(_tracer.offset_plus_k_7(n, _invar, _negate_invar, _offset);)
@@ -3823,11 +4283,15 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) {
if (n->in(2)->is_Con() && invariant(n->in(1))) {
_negate_invar = negate;
_invar = n->in(1);
_offset += !negate ? -(n->in(2)->get_int()) : n->in(2)->get_int();
if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), !negate, _offset)) {
return false; // add/sub overflow.
}
NOT_PRODUCT(_tracer.offset_plus_k_8(n, _invar, _negate_invar, _offset);)
return true;
} else if (n->in(1)->is_Con() && invariant(n->in(2))) {
_offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int();
if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) {
return false; // add/sub overflow.
}
_negate_invar = !negate;
_invar = n->in(2);
NOT_PRODUCT(_tracer.offset_plus_k_9(n, _invar, _negate_invar, _offset);)
@@ -3859,6 +4323,57 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) {
return false;
}
bool SWPointer::try_AddI_no_overflow(jint offset1, jint offset2, jint& result) {
jlong long_offset = java_add((jlong)(offset1), (jlong)(offset2));
jint int_offset = java_add( offset1, offset2);
if (long_offset != int_offset) {
return false;
}
result = int_offset;
return true;
}
bool SWPointer::try_SubI_no_overflow(jint offset1, jint offset2, jint& result) {
jlong long_offset = java_subtract((jlong)(offset1), (jlong)(offset2));
jint int_offset = java_subtract( offset1, offset2);
if (long_offset != int_offset) {
return false;
}
result = int_offset;
return true;
}
bool SWPointer::try_AddSubI_no_overflow(jint offset1, jint offset2, bool is_sub, jint& result) {
if (is_sub) {
return try_SubI_no_overflow(offset1, offset2, result);
} else {
return try_AddI_no_overflow(offset1, offset2, result);
}
}
bool SWPointer::try_LShiftI_no_overflow(jint offset, int shift, jint& result) {
if (shift < 0 || shift > 31) {
return false;
}
jlong long_offset = java_shift_left((jlong)(offset), (julong)((jlong)(shift)));
jint int_offset = java_shift_left( offset, (juint)((jint)(shift)));
if (long_offset != int_offset) {
return false;
}
result = int_offset;
return true;
}
bool SWPointer::try_MulI_no_overflow(jint offset1, jint offset2, jint& result) {
jlong long_offset = java_multiply((jlong)(offset1), (jlong)(offset2));
jint int_offset = java_multiply( offset1, offset2);
if (long_offset != int_offset) {
return false;
}
result = int_offset;
return true;
}
//----------------------------print------------------------
void SWPointer::print() {
#ifndef PRODUCT

View File

@@ -568,17 +568,63 @@ class SuperWord : public ResourceObj {
//------------------------------SWPointer---------------------------
// Information about an address for dependence checking and vector alignment
//
// We parse and represent pointers of the simple form:
//
// pointer = adr + offset + invar + scale * ConvI2L(iv)
//
// Where:
//
// adr: the base address of an array (base = adr)
// OR
// some address to off-heap memory (base = TOP)
//
// offset: a constant offset
// invar: a runtime variable, which is invariant during the loop
// scale: scaling factor
// iv: loop induction variable
//
// But more precisely, we parse the composite-long-int form:
//
// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + inv_invar + int_scale * iv)
//
// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index)
// int_index = int_offset + int_invar + int_scale * iv
//
// However, for aliasing and adjacency checks (e.g. SWPointer::cmp()) we always use the simple form to make
// decisions. Hence, we must make sure to only create a "valid" SWPointer if the optimisations based on the
// simple form produce the same result as the compound-long-int form would. Intuitively, this depends on
// if the int_index overflows, but the precise conditions are given in SWPointer::is_safe_to_use_as_simple_form().
//
// ConvI2L(int_index) = ConvI2L(int_offset + int_invar + int_scale * iv)
// = Convi2L(int_offset) + ConvI2L(int_invar) + ConvI2L(int_scale) * ConvI2L(iv)
//
// scale = long_scale * ConvI2L(int_scale)
// offset = long_offset + long_scale * ConvI2L(int_offset)
// invar = long_invar + long_scale * ConvI2L(int_invar)
//
// pointer = adr + offset + invar + scale * ConvI2L(iv)
//
class SWPointer {
protected:
MemNode* _mem; // My memory reference node
SuperWord* _slp; // SuperWord class
Node* _base; // NULL if unsafe nonheap reference
Node* _adr; // address pointer
// Components of the simple form:
Node* _base; // Base address of an array OR NULL if some off-heap memory.
Node* _adr; // Same as _base if an array pointer OR some off-heap memory pointer.
jint _scale; // multiplier for iv (in bytes), 0 if no loop iv
jint _offset; // constant offset (in bytes)
Node* _invar; // invariant offset (in bytes), NULL if none
bool _negate_invar; // if true then use: (0 - _invar)
// The int_index components of the compound-long-int form. Used to decide if it is safe to use the
// simple form rather than the compound-long-int form that was parsed.
bool _has_int_index_after_convI2L;
int _int_index_after_convI2L_offset;
Node* _int_index_after_convI2L_invar;
int _int_index_after_convI2L_scale;
Node_Stack* _nstack; // stack used to record a swpointer trace of variants
bool _analyze_only; // Used in loop unrolling only for swpointer trace
uint _stack_idx; // Used in loop unrolling only for swpointer trace
@@ -597,6 +643,8 @@ class SWPointer {
// Match: offset is (k [+/- invariant])
bool offset_plus_k(Node* n, bool negate = false);
bool is_safe_to_use_as_simple_form(Node* base, Node* adr) const;
public:
enum CMP {
Less = 1,
@@ -625,12 +673,45 @@ class SWPointer {
Node_Stack* node_stack() { return _nstack; }
// Comparable?
// We compute if and how two SWPointers can alias at runtime, i.e. if the two addressed regions of memory can
// ever overlap. There are essentially 3 relevant return states:
// - NotComparable: Synonymous to "unknown aliasing".
// We have no information about how the two SWPointers can alias. They could overlap, refer
// to another location in the same memory object, or point to a completely different object.
// -> Memory edge required. Aliasing unlikely but possible.
//
// - Less / Greater: Synonymous to "never aliasing".
// The two SWPointers may point into the same memory object, but be non-aliasing (i.e. we
// know both address regions inside the same memory object, but these regions are non-
// overlapping), or the SWPointers point to entirely different objects.
// -> No memory edge required. Aliasing impossible.
//
// - Equal: Synonymous to "overlap, or point to different memory objects".
// The two SWPointers either overlap on the same memory object, or point to two different
// memory objects.
// -> Memory edge required. Aliasing likely.
//
// In a future refactoring, we can simplify to two states:
// - NeverAlias: instead of Less / Greater
// - MayAlias: instead of Equal / NotComparable
//
// Two SWPointer are "comparable" (Less / Greater / Equal), iff all of these conditions apply:
// 1) Both are valid, i.e. expressible in the compound-long-int or simple form.
// 2) The adr are identical, or both are array bases of different arrays.
// 3) They have identical scale.
// 4) They have identical invar.
// 5) The difference in offsets is limited: abs(offset0 - offset1) < 2^31.
int cmp(SWPointer& q) {
if (valid() && q.valid() &&
(_adr == q._adr || (_base == _adr && q._base == q._adr)) &&
_scale == q._scale &&
_invar == q._invar &&
_negate_invar == q._negate_invar) {
jlong difference = abs(java_subtract((jlong)_offset, (jlong)q._offset));
jlong max_diff = (jlong)1 << 31;
if (difference >= max_diff) {
return NotComparable;
}
bool overlap = q._offset < _offset + memory_size() &&
_offset < q._offset + q.memory_size();
return overlap ? Equal : (_offset < q._offset ? Less : Greater);
@@ -717,6 +798,13 @@ class SWPointer {
} _tracer;//TRacer;
#endif
static bool try_AddI_no_overflow(jint offset1, jint offset2, jint& result);
static bool try_SubI_no_overflow(jint offset1, jint offset2, jint& result);
static bool try_AddSubI_no_overflow(jint offset1, jint offset2, bool is_sub, jint& result);
static bool try_LShiftI_no_overflow(jint offset1, int offset2, jint& result);
static bool try_MulI_no_overflow(jint offset1, jint offset2, jint& result);
};
#endif // SHARE_VM_OPTO_SUPERWORD_HPP

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, 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
@@ -36,6 +36,7 @@
#include "utilities/defaultStream.hpp"
#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
#include "logging/logFileStreamOutput.hpp"
#ifdef DTRACE_ENABLED
@@ -191,6 +192,22 @@ bool ClassLoadingService::set_verbose(bool verbose) {
return verbose;
}
bool ClassLoadingService::get_verbose() {
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
// set_verbose looks for a non-exact match for class+load,
// so look for all tag sets that match class+load*
if (ts->contains(LogTag::_class) &&
ts->contains(LogTag::_load)) {
LogLevelType l = ts->level_for(&StdoutLog);
if (l != LogLevel::Info && l != LogLevel::Debug && l != LogLevel::Trace) {
return false;
}
}
}
return true;
}
// Caller to this function must own Management_lock
void ClassLoadingService::reset_trace_class_unloading() {
assert(Management_lock->owned_by_self(), "Must own the Management_lock");

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, 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
@@ -55,8 +55,8 @@ private:
public:
static void init();
static bool get_verbose() { return log_is_enabled(Info, class, load); }
static bool set_verbose(bool verbose);
static bool get_verbose() NOT_MANAGEMENT_RETURN_(false);
static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN;
static jlong loaded_class_count() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, 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
@@ -27,6 +27,7 @@
#include "classfile/vmSymbols.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "logging/logConfiguration.hpp"
#include "logging/logFileStreamOutput.hpp"
#include "memory/heap.hpp"
#include "memory/memRegion.hpp"
#include "memory/resourceArea.hpp"
@@ -215,6 +216,21 @@ bool MemoryService::set_verbose(bool verbose) {
return verbose;
}
bool MemoryService::get_verbose() {
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
// set_verbose only sets gc and not gc*, so check for an exact match
const bool is_gc_exact_match = ts->contains(LogTag::_gc) && ts->ntags() == 1;
if (is_gc_exact_match) {
LogLevelType l = ts->level_for(&StdoutLog);
if (l == LogLevel::Info || l == LogLevel::Debug || l == LogLevel::Trace) {
return true;
}
}
}
return false;
}
Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) {
InstanceKlass* ik = Management::java_lang_management_MemoryUsage_klass(CHECK_NH);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, 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
@@ -107,8 +107,8 @@ public:
static void oops_do(OopClosure* f);
static bool get_verbose() { return log_is_enabled(Info, gc); }
static bool set_verbose(bool verbose);
static bool get_verbose();
// Create an instance of java/lang/management/MemoryUsage
static Handle create_MemoryUsage_obj(MemoryUsage usage, TRAPS);

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2022, 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.
*
*/
// Intentionally no #include guard. May be included multiple times for effect.
// See vmassert_uninstall.hpp for usage.
// Remove possible stdlib assert macro (or any others, for that matter).
#undef assert
// Reinstall HotSpot's assert macro, if previously defined.
#ifdef vmassert
#define assert(p, ...) vmassert(p, __VA_ARGS__)
#endif

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2022, 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.
*
*/
// Intentionally no #include guard. May be included multiple times for effect.
// The files vmassert_uninstall.hpp and vmassert_reinstall.hpp provide a
// workaround for the name collision between HotSpot's assert macro and the
// Standard Library's assert macro. When including a 3rd-party header that
// uses (and so includes) the standard assert macro, wrap that inclusion with
// includes of these two files, e.g.
//
// #include "utilities/vmassert_uninstall.hpp"
// #include <header including standard assert macro>
// #include "utilities/vmassert_reinstall.hpp"
//
// This removes the HotSpot macro definition while pre-processing the
// 3rd-party header, then reinstates the HotSpot macro (if previously defined)
// for following code.
// Remove HotSpot's assert macro, if present.
#ifdef vmassert
#undef assert
#endif // vmassert

View File

@@ -238,6 +238,15 @@ of proxies.</P>
</OL>
<P>The channel binding tokens generated are of the type "tls-server-end-point" as defined in
RFC 5929.</P>
<LI><P><B>{@systemProperty jdk.http.maxHeaderSize}</B> (default: 393216 or 384kB)<BR>
This is the maximum header field section size that a client is prepared to accept.
This is computed as the sum of the size of the uncompressed header name, plus
the size of the uncompressed header value, plus an overhead of 32 bytes for
each field section line. If a peer sends a field section that exceeds this
size a {@link java.net.ProtocolException ProtocolException} will be raised.
This applies to all versions of the HTTP protocol. A value of zero or a negative
value means no limit. If left unspecified, the default value is 393216 bytes.
</UL>
<P>All these properties are checked only once at startup.</P>
<a id="AddressCache"></a>

View File

@@ -41,6 +41,7 @@ package java.text;
import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -982,6 +983,8 @@ public class MessageFormat extends Format {
maximumArgumentNumber = argumentNumbers[i];
}
}
// Constructors/applyPattern ensure that resultArray.length < MAX_ARGUMENT_INDEX
Object[] resultArray = new Object[maximumArgumentNumber + 1];
int patternOffset = 0;
@@ -1232,6 +1235,9 @@ public class MessageFormat extends Format {
* @serial
*/
private int[] argumentNumbers = new int[INITIAL_FORMATS];
// Implementation limit for ArgumentIndex pattern element. Valid indices must
// be less than this value
private static final int MAX_ARGUMENT_INDEX = 10000;
/**
* One less than the number of entries in <code>offsets</code>. Can also be thought of
@@ -1456,6 +1462,11 @@ public class MessageFormat extends Format {
+ argumentNumber);
}
if (argumentNumber >= MAX_ARGUMENT_INDEX) {
throw new IllegalArgumentException(
argumentNumber + " exceeds the ArgumentIndex implementation limit");
}
// resize format information arrays if necessary
if (offsetNumber >= formats.length) {
int newLength = formats.length * 2;
@@ -1602,24 +1613,52 @@ public class MessageFormat extends Format {
* @throws InvalidObjectException if the objects read from the stream is invalid.
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
boolean isValid = maxOffset >= -1
&& formats.length > maxOffset
&& offsets.length > maxOffset
&& argumentNumbers.length > maxOffset;
ObjectInputStream.GetField fields = in.readFields();
if (fields.defaulted("argumentNumbers") || fields.defaulted("offsets")
|| fields.defaulted("formats") || fields.defaulted("locale")
|| fields.defaulted("pattern") || fields.defaulted("maxOffset")){
throw new InvalidObjectException("Stream has missing data");
}
locale = (Locale) fields.get("locale", null);
String patt = (String) fields.get("pattern", null);
int maxOff = fields.get("maxOffset", -2);
int[] argNums = ((int[]) fields.get("argumentNumbers", null)).clone();
int[] offs = ((int[]) fields.get("offsets", null)).clone();
Format[] fmts = ((Format[]) fields.get("formats", null)).clone();
// Check arrays/maxOffset have correct value/length
boolean isValid = maxOff >= -1 && argNums.length > maxOff
&& offs.length > maxOff && fmts.length > maxOff;
// Check the correctness of arguments and offsets
if (isValid) {
int lastOffset = pattern.length() + 1;
for (int i = maxOffset; i >= 0; --i) {
if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
int lastOffset = patt.length() + 1;
for (int i = maxOff; i >= 0; --i) {
if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX
|| offs[i] < 0 || offs[i] > lastOffset) {
isValid = false;
break;
} else {
lastOffset = offsets[i];
lastOffset = offs[i];
}
}
}
if (!isValid) {
throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
throw new InvalidObjectException("Stream has invalid data");
}
maxOffset = maxOff;
pattern = patt;
offsets = offs;
formats = fmts;
argumentNumbers = argNums;
}
/**
* Serialization without data not supported for this class.
*/
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("Deserialized MessageFormat objects need data");
}
}

View File

@@ -30,6 +30,8 @@
package sun.net.www;
import java.io.*;
import java.lang.reflect.Array;
import java.net.ProtocolException;
import java.util.Collections;
import java.util.*;
@@ -46,11 +48,32 @@ class MessageHeader {
private String values[];
private int nkeys;
// max number of bytes for headers, <=0 means unlimited;
// this corresponds to the length of the names, plus the length
// of the values, plus an overhead of 32 bytes per name: value
// pair.
// Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE
// see RFC 9113, section 6.5.2.
// https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE
private final int maxHeaderSize;
// Aggregate size of the field lines (name + value + 32) x N
// that have been parsed and accepted so far.
// This is defined as a long to force promotion to long
// and avoid overflows; see checkNewSize;
private long size;
public MessageHeader () {
this(0);
}
public MessageHeader (int maxHeaderSize) {
this.maxHeaderSize = maxHeaderSize;
grow();
}
public MessageHeader (InputStream is) throws java.io.IOException {
maxHeaderSize = 0;
parseHeader(is);
}
@@ -466,10 +489,28 @@ class MessageHeader {
public void parseHeader(InputStream is) throws java.io.IOException {
synchronized (this) {
nkeys = 0;
size = 0;
}
mergeHeader(is);
}
private void checkMaxHeaderSize(int sz) throws ProtocolException {
if (maxHeaderSize > 0) checkNewSize(size, sz, 0);
}
private long checkNewSize(long size, int name, int value) throws ProtocolException {
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
long newSize = size + name + value + 32;
if (maxHeaderSize > 0 && newSize > maxHeaderSize) {
Arrays.fill(keys, 0, nkeys, null);
Arrays.fill(values,0, nkeys, null);
nkeys = 0;
throw new ProtocolException(String.format("Header size too big: %s > %s",
newSize, maxHeaderSize));
}
return newSize;
}
/** Parse and merge a MIME header from an input stream. */
@SuppressWarnings("fallthrough")
public void mergeHeader(InputStream is) throws java.io.IOException {
@@ -483,7 +524,15 @@ class MessageHeader {
int c;
boolean inKey = firstc > ' ';
s[len++] = (char) firstc;
checkMaxHeaderSize(len);
parseloop:{
// We start parsing for a new name value pair here.
// The max header size includes an overhead of 32 bytes per
// name value pair.
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
long maxRemaining = maxHeaderSize > 0
? maxHeaderSize - size - 32
: Long.MAX_VALUE;
while ((c = is.read()) >= 0) {
switch (c) {
case ':':
@@ -517,6 +566,9 @@ class MessageHeader {
s = ns;
}
s[len++] = (char) c;
if (maxHeaderSize > 0 && len > maxRemaining) {
checkMaxHeaderSize(len);
}
}
firstc = -1;
}
@@ -538,6 +590,9 @@ class MessageHeader {
v = new String();
else
v = String.copyValueOf(s, keyend, len - keyend);
int klen = k == null ? 0 : k.length();
size = checkNewSize(size, klen, v.length());
add(k, v);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2024, 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
@@ -169,6 +169,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/
private static int bufSize4ES = 0;
private static final int maxHeaderSize;
/*
* Restrict setting of request headers through the public api
* consistent with JavaScript XMLHttpRequest2 with a few
@@ -282,10 +284,24 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
} else {
restrictedHeaderSet = null;
}
int defMaxHeaderSize = 384 * 1024;
String maxHeaderSizeStr = getNetProperty("jdk.http.maxHeaderSize");
int maxHeaderSizeVal = defMaxHeaderSize;
if (maxHeaderSizeStr != null) {
try {
maxHeaderSizeVal = Integer.parseInt(maxHeaderSizeStr);
} catch (NumberFormatException n) {
maxHeaderSizeVal = defMaxHeaderSize;
}
}
if (maxHeaderSizeVal < 0) maxHeaderSizeVal = 0;
maxHeaderSize = maxHeaderSizeVal;
}
static final String httpVersion = "HTTP/1.1";
static final String acceptString = "*/*";
static final String acceptString =
"text/html, image/gif, image/jpeg, */*; q=0.2";
// the following http request headers should NOT have their values
// returned for security reasons.
@@ -724,7 +740,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
}
ps = (PrintStream) http.getOutputStream();
connected=true;
responses = new MessageHeader();
responses = new MessageHeader(maxHeaderSize);
setRequests=false;
writeRequests();
}
@@ -879,7 +895,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
throws IOException {
super(checkURL(u));
requests = new MessageHeader();
responses = new MessageHeader();
responses = new MessageHeader(maxHeaderSize);
userHeaders = new MessageHeader();
this.handler = handler;
instProxy = p;
@@ -2766,7 +2782,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
}
// clear out old response headers!!!!
responses = new MessageHeader();
responses = new MessageHeader(maxHeaderSize);
if (stat == HTTP_USE_PROXY) {
/* This means we must re-request the resource through the
* proxy denoted in the "Location:" field of the response.
@@ -2955,7 +2971,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
} catch (IOException e) { }
}
responseCode = -1;
responses = new MessageHeader();
responses = new MessageHeader(maxHeaderSize);
connected = false;
}

View File

@@ -218,8 +218,6 @@ final class ClientHello {
// ignore cookie
hos.putBytes16(getEncodedCipherSuites());
hos.putBytes8(compressionMethod);
extensions.send(hos); // In TLS 1.3, use of certain
// extensions is mandatory.
} catch (IOException ioe) {
// unlikely
}
@@ -1390,6 +1388,9 @@ final class ClientHello {
shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,
SSLHandshake.SERVER_HELLO);
// Reset the ClientHello non-zero offset fragment allowance
shc.acceptCliHelloFragments = false;
//
// produce
//

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2024, 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
@@ -28,13 +28,7 @@ package sun.security.ssl;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import javax.crypto.BadPaddingException;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLProtocolException;
@@ -46,12 +40,23 @@ import sun.security.ssl.SSLCipher.SSLReadCipher;
final class DTLSInputRecord extends InputRecord implements DTLSRecord {
private DTLSReassembler reassembler = null;
private int readEpoch;
private SSLContextImpl sslContext;
DTLSInputRecord(HandshakeHash handshakeHash) {
super(handshakeHash, SSLReadCipher.nullDTlsReadCipher());
this.readEpoch = 0;
}
// Method to set TransportContext
public void setTransportContext(TransportContext tc) {
this.tc = tc;
}
// Method to set SSLContext
public void setSSLContext(SSLContextImpl sslContext) {
this.sslContext = sslContext;
}
@Override
void changeReadCiphers(SSLReadCipher readCipher) {
this.readCipher = readCipher;
@@ -544,6 +549,27 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
}
}
/**
* Turn a sufficiently-large initial ClientHello fragment into one that
* stops immediately after the compression methods. This is only used
* for the initial CH message fragment at offset 0.
*
* @param srcFrag the fragment actually received by the DTLSReassembler
* @param limit the size of the new, cloned/truncated handshake fragment
*
* @return a truncated handshake fragment that is sized to look like a
* complete message, but actually contains only up to the compression
* methods (no extensions)
*/
private static HandshakeFragment truncateChFragment(HandshakeFragment srcFrag,
int limit) {
return new HandshakeFragment(Arrays.copyOf(srcFrag.fragment, limit),
srcFrag.contentType, srcFrag.majorVersion,
srcFrag.minorVersion, srcFrag.recordEnS, srcFrag.recordEpoch,
srcFrag.recordSeq, srcFrag.handshakeType, limit,
srcFrag.messageSeq, srcFrag.fragmentOffset, limit);
}
private static final class HoleDescriptor {
int offset; // fragment_offset
int limit; // fragment_offset + fragment_length
@@ -647,10 +673,17 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
// Queue up a handshake message.
void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException {
if (!isDesirable(hsf)) {
// Not a dedired record, discard it.
// Not a desired record, discard it.
return;
}
if (hsf.handshakeType == SSLHandshake.CLIENT_HELLO.id) {
// validate the first or subsequent ClientHello message
if ((hsf = valHello(hsf, hsf.messageSeq == 0)) == null) {
return;
}
}
// Clean up the retransmission messages if necessary.
cleanUpRetransmit(hsf);
@@ -783,6 +816,100 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
}
}
private HandshakeFragment valHello(HandshakeFragment hsf,
boolean firstHello) {
ServerHandshakeContext shc =
(ServerHandshakeContext) tc.handshakeContext;
// Drop any fragment that is not a zero offset until we've received
// a second (or possibly later) CH message that passes the cookie
// check.
if (shc == null || !shc.acceptCliHelloFragments) {
if (hsf.fragmentOffset != 0) {
return null;
}
} else {
// Let this fragment through to the DTLSReassembler as-is
return hsf;
}
try {
ByteBuffer fragmentData = ByteBuffer.wrap(hsf.fragment);
ProtocolVersion pv = ProtocolVersion.valueOf(
Record.getInt16(fragmentData));
if (!pv.isDTLS) {
return null;
}
// Read the random (32 bytes)
if (fragmentData.remaining() < 32) {
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
SSLLogger.fine("Rejected client hello fragment (bad random len) " +
"fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
}
return null;
}
fragmentData.position(fragmentData.position() + 32);
// SessionID
byte[] sessId = Record.getBytes8(fragmentData);
if (sessId.length > 0 &&
!SSLConfiguration.enableDtlsResumeCookie) {
// If we are in a resumption it is possible that the cookie
// exchange will be skipped. This is a server-side setting
// and it is NOT the default. If enableDtlsResumeCookie is
// false though, then we will buffer fragments since there
// is no cookie exchange to execute prior to performing
// reassembly.
return hsf;
}
// Cookie
byte[] cookie = Record.getBytes8(fragmentData);
if (firstHello && cookie.length != 0) {
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
SSLLogger.fine("Rejected initial client hello fragment (bad cookie len) " +
"fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
}
return null;
}
// CipherSuites
Record.getBytes16(fragmentData);
// Compression methods
Record.getBytes8(fragmentData);
// If it's the first fragment, we'll truncate it and push it
// through the reassembler.
if (firstHello) {
return truncateChFragment(hsf, fragmentData.position());
} else {
HelloCookieManager hcMgr = sslContext.
getHelloCookieManager(ProtocolVersion.DTLS10);
ByteBuffer msgFragBuf = ByteBuffer.wrap(hsf.fragment, 0,
fragmentData.position());
ClientHello.ClientHelloMessage chMsg =
new ClientHello.ClientHelloMessage(shc, msgFragBuf, null);
if (!hcMgr.isCookieValid(shc, chMsg, cookie)) {
// Bad cookie check, truncate it and let the ClientHello
// consumer recheck, fail and take the appropriate action.
return truncateChFragment(hsf, fragmentData.position());
} else {
// It's a good cookie, return the original handshake
// fragment and let it go into the DTLSReassembler like
// any other fragment so we can wait for the rest of
// the CH message.
shc.acceptCliHelloFragments = true;
return hsf;
}
}
} catch (IOException ioe) {
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
SSLLogger.fine("Rejected client hello fragment " +
"fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
}
return null;
}
}
// Queue up a ChangeCipherSpec message
void queueUpChangeCipherSpec(RecordFragment rf)
throws SSLProtocolException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@@ -55,6 +55,7 @@ class ServerHandshakeContext extends HandshakeContext {
CertificateMessage.CertificateEntry currentCertEntry;
private static final long DEFAULT_STATUS_RESP_DELAY = 5000L;
final long statusRespTimeout;
boolean acceptCliHelloFragments = false;
ServerHandshakeContext(SSLContextImpl sslContext,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@@ -138,6 +138,12 @@ class TransportContext implements ConnectionContext {
this.acc = AccessController.getContext();
this.consumers = new HashMap<>();
if (inputRecord instanceof DTLSInputRecord) {
DTLSInputRecord dtlsInputRecord = (DTLSInputRecord)inputRecord;
dtlsInputRecord.setTransportContext(this);
dtlsInputRecord.setSSLContext(this.sslContext);
}
}
// Dispatch plaintext to a specific consumer.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@@ -53,6 +53,22 @@ enum CADistrustPolicy {
}
SymantecTLSPolicy.checkDistrust(chain);
}
},
/**
* Distrust TLS Server certificates anchored by an Entrust root CA and
* issued after November 11, 2024. If enabled, this policy is currently
* enforced by the PKIX and SunX509 TrustManager implementations
* of the SunJSSE provider implementation.
*/
ENTRUST_TLS {
void checkDistrust(String variant, X509Certificate[] chain)
throws ValidatorException {
if (!variant.equals(Validator.VAR_TLS_SERVER)) {
return;
}
EntrustTLSPolicy.checkDistrust(chain);
}
};
/**

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2024, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.security.validator;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import sun.security.util.Debug;
import sun.security.x509.X509CertImpl;
/**
* This class checks if Entrust issued TLS Server certificates should be
* restricted.
*/
final class EntrustTLSPolicy {
private static final Debug debug = Debug.getInstance("certpath");
// SHA-256 certificate fingerprints of distrusted roots
private static final Set<String> FINGERPRINTS = Set.of(
// cacerts alias: entrustevca
// DN: CN=Entrust Root Certification Authority,
// OU=(c) 2006 Entrust, Inc.,
// OU=www.entrust.net/CPS is incorporated by reference,
// O=Entrust, Inc., C=US
"73C176434F1BC6D5ADF45B0E76E727287C8DE57616C1E6E6141A2B2CBC7D8E4C",
// cacerts alias: entrustrootcaec1
// DN: CN=Entrust Root Certification Authority - EC1,
// OU=(c) 2012 Entrust, Inc. - for authorized use only,
// OU=See www.entrust.net/legal-terms, O=Entrust, Inc., C=US
"02ED0EB28C14DA45165C566791700D6451D7FB56F0B2AB1D3B8EB070E56EDFF5",
// cacerts alias: entrustrootcag2
// DN: CN=Entrust Root Certification Authority - G2,
// OU=(c) 2009 Entrust, Inc. - for authorized use only,
// OU=See www.entrust.net/legal-terms, O=Entrust, Inc., C=US
"43DF5774B03E7FEF5FE40D931A7BEDF1BB2E6B42738C4E6D3841103D3AA7F339",
// cacerts alias: entrustrootcag4
// DN: CN=Entrust Root Certification Authority - G4
// OU=(c) 2015 Entrust, Inc. - for authorized use only,
// OU=See www.entrust.net/legal-terms, O=Entrust, Inc., C=US,
"DB3517D1F6732A2D5AB97C533EC70779EE3270A62FB4AC4238372460E6F01E88",
// cacerts alias: entrust2048ca
// DN: CN=Entrust.net Certification Authority (2048),
// OU=(c) 1999 Entrust.net Limited,
// OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.),
// O=Entrust.net
"6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177",
// cacerts alias: affirmtrustcommercialca
// DN: CN=AffirmTrust Commercial, O=AffirmTrust, C=US
"0376AB1D54C5F9803CE4B2E201A0EE7EEF7B57B636E8A93C9B8D4860C96F5FA7",
// cacerts alias: affirmtrustnetworkingca
// DN: CN=AffirmTrust Networking, O=AffirmTrust, C=US
"0A81EC5A929777F145904AF38D5D509F66B5E2C58FCDB531058B0E17F3F0B41B",
// cacerts alias: affirmtrustpremiumca
// DN: CN=AffirmTrust Premium, O=AffirmTrust, C=US
"70A73F7F376B60074248904534B11482D5BF0E698ECC498DF52577EBF2E93B9A",
// cacerts alias: affirmtrustpremiumeccca
// DN: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US
"BD71FDF6DA97E4CF62D1647ADD2581B07D79ADF8397EB4ECBA9C5E8488821423"
);
// Any TLS Server certificate that is anchored by one of the Entrust
// roots above and is issued after this date will be distrusted.
private static final LocalDate NOVEMBER_11_2024 =
LocalDate.of(2024, Month.NOVEMBER, 11);
/**
* This method assumes the eeCert is a TLS Server Cert and chains back to
* the anchor.
*
* @param chain the end-entity's certificate chain. The end entity cert
* is at index 0, the trust anchor at index n-1.
* @throws ValidatorException if the certificate is distrusted
*/
static void checkDistrust(X509Certificate[] chain)
throws ValidatorException {
X509Certificate anchor = chain[chain.length-1];
String fp = fingerprint(anchor);
if (fp == null) {
throw new ValidatorException("Cannot generate fingerprint for "
+ "trust anchor of TLS server certificate");
}
if (FINGERPRINTS.contains(fp)) {
Date notBefore = chain[0].getNotBefore();
LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(),
ZoneOffset.UTC);
// reject if certificate is issued after November 11, 2024
checkNotBefore(ldNotBefore, NOVEMBER_11_2024, anchor);
}
}
private static String fingerprint(X509Certificate cert) {
return X509CertImpl.getFingerprint("SHA-256", cert);
}
private static void checkNotBefore(LocalDate notBeforeDate,
LocalDate distrustDate, X509Certificate anchor)
throws ValidatorException {
if (notBeforeDate.isAfter(distrustDate)) {
throw new ValidatorException
("TLS Server certificate issued after " + distrustDate +
" and anchored by a distrusted legacy Entrust root CA: "
+ anchor.getSubjectX500Principal(),
ValidatorException.T_UNTRUSTED_CERT, anchor);
}
}
private EntrustTLSPolicy() {}
}

View File

@@ -137,3 +137,20 @@ jdk.http.auth.tunneling.disabledSchemes=Basic
#jdk.http.ntlm.transparentAuth=trustedHosts
#
jdk.http.ntlm.transparentAuth=disabled
#
# Maximum HTTP field section size that a client is prepared to accept
#
# jdk.http.maxHeaderSize=393216
#
# This is the maximum header field section size that a client is prepared to accept.
# This is computed as the sum of the size of the uncompressed header name, plus
# the size of the uncompressed header value, plus an overhead of 32 bytes for
# each field section line. If a peer sends a field section that exceeds this
# size a {@link java.net.ProtocolException ProtocolException} will be raised.
# This applies to all versions of the HTTP protocol. A value of zero or a negative
# value means no limit. If left unspecified, the default value is 393216 bytes
# or 384kB.
#
# Note: This property is currently used by the JDK Reference implementation. It
# is not guaranteed to be examined and used by other implementations.

View File

@@ -1287,6 +1287,9 @@ jdk.sasl.disabledMechanisms=
# A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED
# Distrust after December 31, 2019.
#
# ENTRUST_TLS : Distrust TLS Server certificates anchored by
# an Entrust root CA and issued after November 11, 2024.
#
# Leading and trailing whitespace surrounding each value are ignored.
# Unknown values are ignored. If the property is commented out or set to the
# empty String, no policies are enforced.
@@ -1298,7 +1301,7 @@ jdk.sasl.disabledMechanisms=
# jdk.certpath.disabledAlgorithms; those restrictions are still enforced even
# if this property is not enabled.
#
jdk.security.caDistrustPolicies=SYMANTEC_TLS
jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS
#
# FilePermission path canonicalization

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -239,6 +239,10 @@ final class Obj {
ClassLoader cl = helper.getURLClassLoader(codebases);
return deserializeObject((byte[])attr.get(), cl);
} else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) {
// javaRemoteLocation attribute (RMI stub will be created)
if (!VersionHelper.isSerialDataAllowed()) {
throw new NamingException("Object deserialization is not allowed");
}
// For backward compatibility only
return decodeRmiObject(
(String)attrs.get(JAVA_ATTRIBUTES[CLASSNAME]).get(),

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@@ -44,8 +44,8 @@ public final class VersionHelper {
private static final boolean trustURLCodebase;
/**
* Determines whether objects may be deserialized from the content of
* 'javaSerializedData' attribute.
* Determines whether objects may be deserialized or reconstructed from a content of
* 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' LDAP attributes.
*/
private static final boolean trustSerialData;
@@ -56,10 +56,10 @@ public final class VersionHelper {
"com.sun.jndi.ldap.object.trustURLCodebase", "false");
trustURLCodebase = "true".equalsIgnoreCase(trust);
// System property to control whether classes is allowed to be loaded from
// 'javaSerializedData' attribute
// System property to control whether classes are allowed to be loaded from
// 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' attributes.
String trustSerialDataSp = getPrivilegedProperty(
"com.sun.jndi.ldap.object.trustSerialData", "true");
"com.sun.jndi.ldap.object.trustSerialData", "false");
trustSerialData = "true".equalsIgnoreCase(trustSerialDataSp);
}
@@ -80,8 +80,9 @@ public final class VersionHelper {
}
/**
* Returns true if deserialization of objects from 'javaSerializedData'
* and 'javaReferenceAddress' LDAP attributes is allowed.
* Returns true if deserialization or reconstruction of objects from
* 'javaSerializedData', 'javaRemoteLocation' and 'javaReferenceAddress'
* LDAP attributes is allowed.
*
* @return true if deserialization is allowed; false - otherwise
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2024, 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
@@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
@@ -68,6 +69,8 @@ import static jdk.internal.net.http.common.Utils.permissionForProxy;
*/
final class Exchange<T> {
static final int MAX_NON_FINAL_RESPONSES =
Utils.getIntegerNetProperty("jdk.httpclient.maxNonFinalResponses", 8);
final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG);
final HttpRequestImpl request;
@@ -90,6 +93,8 @@ final class Exchange<T> {
// exchange so that it can be aborted/timed out mid setup.
final ConnectionAborter connectionAborter = new ConnectionAborter();
final AtomicInteger nonFinalResponses = new AtomicInteger();
Exchange(HttpRequestImpl request, MultiExchange<T> multi) {
this.request = request;
this.upgrading = false;
@@ -281,7 +286,7 @@ final class Exchange<T> {
public void h2Upgrade() {
upgrading = true;
request.setH2Upgrade(client.client2());
request.setH2Upgrade(this);
}
synchronized IOException getCancelCause() {
@@ -379,6 +384,7 @@ final class Exchange<T> {
Log.logResponse(r1::toString);
int rcode = r1.statusCode();
if (rcode == 100) {
nonFinalResponses.incrementAndGet();
Log.logTrace("Received 100-Continue: sending body");
if (debug.on()) debug.log("Received 100-Continue for %s", r1);
CompletableFuture<Response> cf =
@@ -455,12 +461,20 @@ final class Exchange<T> {
+ rsp.statusCode());
}
assert exchImpl != null : "Illegal state - current exchange isn't set";
// ignore this Response and wait again for the subsequent response headers
final CompletableFuture<Response> cf = exchImpl.getResponseAsync(parentExecutor);
// we recompose the CF again into the ignore1xxResponse check/function because
// the 1xx response is allowed to be sent multiple times for a request, before
// a final response arrives
return cf.thenCompose(this::ignore1xxResponse);
int count = nonFinalResponses.incrementAndGet();
if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) {
return MinimalFuture.failedFuture(
new ProtocolException(String.format(
"Too many interim responses received: %s > %s",
count, MAX_NON_FINAL_RESPONSES)));
} else {
// ignore this Response and wait again for the subsequent response headers
final CompletableFuture<Response> cf = exchImpl.getResponseAsync(parentExecutor);
// we recompose the CF again into the ignore1xxResponse check/function because
// the 1xx response is allowed to be sent multiple times for a request, before
// a final response arrives
return cf.thenCompose(this::ignore1xxResponse);
}
} else {
// return the already completed future
return MinimalFuture.completedFuture(rsp);
@@ -562,7 +576,7 @@ final class Exchange<T> {
this, e::drainLeftOverBytes)
.thenCompose((Http2Connection c) -> {
boolean cached = c.offerConnection();
Stream<T> s = c.getStream(1);
Stream<T> s = c.getInitialStream();
if (s == null) {
// s can be null if an exception occurred
@@ -717,6 +731,14 @@ final class Exchange<T> {
return multi.version();
}
boolean pushEnabled() {
return pushGroup != null;
}
String h2cSettingsStrings() {
return client.client2().getSettingsString(pushEnabled());
}
String dbgString() {
return dbgTag;
}

View File

@@ -25,6 +25,7 @@
package jdk.internal.net.http;
import java.io.IOException;
import java.net.ProtocolException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -33,6 +34,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.net.http.HttpHeaders;
import jdk.internal.net.http.common.Utils;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static jdk.internal.net.http.common.Utils.ACCEPT_ALL;
@@ -49,6 +51,12 @@ class Http1HeaderParser {
private int responseCode;
private HttpHeaders headers;
private Map<String,List<String>> privateMap = new HashMap<>();
private long size;
private static final int K = 1024;
private static final int MAX_HTTP_HEADER_SIZE = Utils.getIntegerNetProperty(
"jdk.http.maxHeaderSize",
Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K, true);
enum State { INITIAL,
STATUS_LINE,
@@ -166,11 +174,16 @@ class Http1HeaderParser {
}
}
private void readResumeStatusLine(ByteBuffer input) {
private void readResumeStatusLine(ByteBuffer input) throws ProtocolException {
final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length();
int count = 0;
char c = 0;
while (input.hasRemaining() && (c =(char)input.get()) != CR) {
if (c == LF) break;
sb.append(c);
if (++count > max) {
checkMaxHeaderSize(sb.length());
}
}
if (c == CR) {
state = State.STATUS_LINE_FOUND_CR;
@@ -187,6 +200,7 @@ class Http1HeaderParser {
}
statusLine = sb.toString();
size = size + 32 + statusLine.length();
sb = new StringBuilder();
if (!statusLine.startsWith("HTTP/1.")) {
throw protocolException("Invalid status line: \"%s\"", statusLine);
@@ -199,7 +213,23 @@ class Http1HeaderParser {
state = State.STATUS_LINE_END;
}
private void maybeStartHeaders(ByteBuffer input) {
private void checkMaxHeaderSize(int sz) throws ProtocolException {
long s = size + sz + 32;
if (MAX_HTTP_HEADER_SIZE > 0 && s > MAX_HTTP_HEADER_SIZE) {
throw new ProtocolException(String.format("Header size too big: %s > %s",
s, MAX_HTTP_HEADER_SIZE));
}
}
static private long newSize(long size, int name, int value) throws ProtocolException {
long newSize = size + name + value + 32;
if (MAX_HTTP_HEADER_SIZE > 0 && newSize > MAX_HTTP_HEADER_SIZE) {
throw new ProtocolException(String.format("Header size too big: %s > %s",
newSize, MAX_HTTP_HEADER_SIZE));
}
return newSize;
}
private void maybeStartHeaders(ByteBuffer input) throws ProtocolException {
assert state == State.STATUS_LINE_END;
assert sb.length() == 0;
char c = (char)input.get();
@@ -209,6 +239,7 @@ class Http1HeaderParser {
state = State.STATUS_LINE_END_LF;
} else {
sb.append(c);
checkMaxHeaderSize(sb.length());
state = State.HEADER;
}
}
@@ -226,9 +257,11 @@ class Http1HeaderParser {
}
}
private void readResumeHeader(ByteBuffer input) {
private void readResumeHeader(ByteBuffer input) throws ProtocolException {
assert state == State.HEADER;
assert input.hasRemaining();
final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length();
int count = 0;
while (input.hasRemaining()) {
char c = (char)input.get();
if (c == CR) {
@@ -242,10 +275,13 @@ class Http1HeaderParser {
if (c == HT)
c = SP;
sb.append(c);
if (++count > max) {
checkMaxHeaderSize(sb.length());
}
}
}
private void addHeaderFromString(String headerString) {
private void addHeaderFromString(String headerString) throws ProtocolException {
assert sb.length() == 0;
int idx = headerString.indexOf(':');
if (idx == -1)
@@ -254,12 +290,12 @@ class Http1HeaderParser {
if (name.isEmpty())
return;
String value = headerString.substring(idx + 1, headerString.length()).trim();
size = newSize(size, name.length(), value.length());
privateMap.computeIfAbsent(name.toLowerCase(Locale.US),
k -> new ArrayList<>()).add(value);
}
private void resumeOrLF(ByteBuffer input) {
private void resumeOrLF(ByteBuffer input) throws ProtocolException {
assert state == State.HEADER_FOUND_CR || state == State.HEADER_FOUND_LF;
char c = state == State.HEADER_FOUND_LF ? LF : (char)input.get();
if (c == LF) {
@@ -269,15 +305,17 @@ class Http1HeaderParser {
state = State.HEADER_FOUND_CR_LF;
} else if (c == SP || c == HT) {
sb.append(SP); // parity with MessageHeaders
checkMaxHeaderSize(sb.length());
state = State.HEADER;
} else {
sb = new StringBuilder();
sb.append(c);
checkMaxHeaderSize(1);
state = State.HEADER;
}
}
private void resumeOrSecondCR(ByteBuffer input) {
private void resumeOrSecondCR(ByteBuffer input) throws ProtocolException {
assert state == State.HEADER_FOUND_CR_LF;
char c = (char)input.get();
if (c == CR || c == LF) {
@@ -298,6 +336,7 @@ class Http1HeaderParser {
} else if (c == SP || c == HT) {
assert sb.length() != 0;
sb.append(SP); // continuation line
checkMaxHeaderSize(sb.length());
state = State.HEADER;
} else {
if (sb.length() > 0) {
@@ -308,6 +347,7 @@ class Http1HeaderParser {
addHeaderFromString(headerString);
}
sb.append(c);
checkMaxHeaderSize(sb.length());
state = State.HEADER;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2024, 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
@@ -38,7 +38,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CompletableFuture;
import jdk.internal.net.http.common.Log;
import jdk.internal.net.http.common.Logger;
import jdk.internal.net.http.common.MinimalFuture;
import jdk.internal.net.http.common.Utils;
@@ -48,6 +47,7 @@ import static jdk.internal.net.http.frame.SettingsFrame.ENABLE_PUSH;
import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE;
import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS;
import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE;
import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE;
/**
* Http2 specific aspects of HttpClientImpl
@@ -94,14 +94,19 @@ class Http2ClientImpl {
CompletableFuture<Http2Connection> getConnectionFor(HttpRequestImpl req,
Exchange<?> exchange) {
String key = Http2Connection.keyFor(req);
boolean pushEnabled = exchange.pushEnabled();
synchronized (this) {
Http2Connection connection = connections.get(key);
if (connection != null) {
try {
if (connection.closed || !connection.reserveStream(true)) {
if (connection.closed
|| !connection.reserveStream(true, pushEnabled)) {
if (debug.on())
debug.log("removing found closed or closing connection: %s", connection);
debug.log("removing connection from pool since " +
"it couldn't be reserved for use%s: %s",
pushEnabled ? " with server push enabled" :
"", connection);
deleteConnection(connection);
} else {
// fast path if connection already exists
@@ -128,7 +133,7 @@ class Http2ClientImpl {
synchronized (Http2ClientImpl.this) {
if (conn != null) {
try {
conn.reserveStream(true);
conn.reserveStream(true, exchange.pushEnabled());
} catch (IOException e) {
throw new UncheckedIOException(e); // shouldn't happen
}
@@ -161,10 +166,21 @@ class Http2ClientImpl {
synchronized(this) {
Http2Connection c1 = connections.putIfAbsent(key, c);
if (c1 != null) {
c.setFinalStream();
if (debug.on())
debug.log("existing entry in connection pool for %s", key);
return false;
if (c.serverPushEnabled() && !c1.serverPushEnabled()) {
c1.setFinalStream();
connections.remove(key, c1);
connections.put(key, c);
if (debug.on()) {
debug.log("Replacing %s with %s in connection pool", c1, c);
}
if (c1.shouldClose()) c1.close();
return true;
} else {
c.setFinalStream();
if (debug.on())
debug.log("existing entry in connection pool for %s", key);
return false;
}
}
if (debug.on())
debug.log("put in the connection pool: %s", c);
@@ -204,8 +220,8 @@ class Http2ClientImpl {
}
/** Returns the client settings as a base64 (url) encoded string */
String getSettingsString() {
SettingsFrame sf = getClientSettings();
String getSettingsString(boolean defaultServerPush) {
SettingsFrame sf = getClientSettings(defaultServerPush);
byte[] settings = sf.toByteArray(); // without the header
Base64.Encoder encoder = Base64.getUrlEncoder()
.withoutPadding();
@@ -215,14 +231,7 @@ class Http2ClientImpl {
private static final int K = 1024;
private static int getParameter(String property, int min, int max, int defaultValue) {
int value = Utils.getIntegerNetProperty(property, defaultValue);
// use default value if misconfigured
if (value < min || value > max) {
Log.logError("Property value for {0}={1} not in [{2}..{3}]: " +
"using default={4}", property, value, min, max, defaultValue);
value = defaultValue;
}
return value;
return Utils.getIntegerNetProperty(property, min, max, defaultValue, true);
}
// used for the connection window, to have a connection window size
@@ -243,7 +252,18 @@ class Http2ClientImpl {
streamWindow, Integer.MAX_VALUE, defaultValue);
}
SettingsFrame getClientSettings() {
/**
* This method is used to test whether pushes are globally
* disabled on all connections.
* @return true if pushes are globally disabled on all connections
*/
boolean serverPushDisabled() {
return getParameter(
"jdk.httpclient.enablepush",
0, 1, 1) == 0;
}
SettingsFrame getClientSettings(boolean defaultServerPush) {
SettingsFrame frame = new SettingsFrame();
// default defined for HTTP/2 is 4 K, we use 16 K.
frame.setParameter(HEADER_TABLE_SIZE, getParameter(
@@ -252,14 +272,15 @@ class Http2ClientImpl {
// O: does not accept push streams. 1: accepts push streams.
frame.setParameter(ENABLE_PUSH, getParameter(
"jdk.httpclient.enablepush",
0, 1, 1));
0, 1, defaultServerPush ? 1 : 0));
// HTTP/2 recommends to set the number of concurrent streams
// no lower than 100. We use 100. 0 means no stream would be
// accepted. That would render the client to be non functional,
// so we won't let 0 be configured for our Http2ClientImpl.
// no lower than 100. We use 100, unless push promises are
// disabled.
int initialServerStreams = frame.getParameter(ENABLE_PUSH) == 0
? 0 : 100;
frame.setParameter(MAX_CONCURRENT_STREAMS, getParameter(
"jdk.httpclient.maxstreams",
1, Integer.MAX_VALUE, 100));
0, Integer.MAX_VALUE, initialServerStreams));
// Maximum size is 2^31-1. Don't allow window size to be less
// than the minimum frame size as this is likely to be a
// configuration error. HTTP/2 specify a default of 64 * K -1,
@@ -272,6 +293,14 @@ class Http2ClientImpl {
frame.setParameter(MAX_FRAME_SIZE, getParameter(
"jdk.httpclient.maxframesize",
16 * K, 16 * K * K -1, 16 * K));
// Maximum field section size we're prepared to accept
// This is the uncompressed name + value size + 32 per field line
int maxHeaderSize = getParameter(
"jdk.http.maxHeaderSize",
Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K);
// If the property is <= 0 the value is unlimited
if (maxHeaderSize <= 0) maxHeaderSize = -1;
frame.setParameter(MAX_HEADER_LIST_SIZE, maxHeaderSize);
return frame;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2024, 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
@@ -29,6 +29,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetSocketAddress;
import java.net.ProtocolException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -44,6 +45,8 @@ import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Flow;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.net.ssl.SSLEngine;
@@ -53,12 +56,14 @@ import java.net.http.HttpHeaders;
import jdk.internal.net.http.HttpConnection.HttpPublisher;
import jdk.internal.net.http.common.FlowTube;
import jdk.internal.net.http.common.FlowTube.TubeSubscriber;
import jdk.internal.net.http.common.HeaderDecoder;
import jdk.internal.net.http.common.HttpHeadersBuilder;
import jdk.internal.net.http.common.Log;
import jdk.internal.net.http.common.Logger;
import jdk.internal.net.http.common.MinimalFuture;
import jdk.internal.net.http.common.SequentialScheduler;
import jdk.internal.net.http.common.Utils;
import jdk.internal.net.http.common.ValidatingHeadersConsumer;
import jdk.internal.net.http.frame.ContinuationFrame;
import jdk.internal.net.http.frame.DataFrame;
import jdk.internal.net.http.frame.ErrorFrame;
@@ -243,6 +248,55 @@ class Http2Connection {
}
}
private final class PushContinuationState {
final PushPromiseDecoder pushContDecoder;
final PushPromiseFrame pushContFrame;
PushContinuationState(PushPromiseDecoder pushContDecoder, PushPromiseFrame pushContFrame) {
this.pushContDecoder = pushContDecoder;
this.pushContFrame = pushContFrame;
}
}
private final class PushPromiseDecoder extends HeaderDecoder implements DecodingCallback {
final int parentStreamId;
final int pushPromiseStreamId;
final Stream<?> parent;
final AtomicReference<Throwable> errorRef = new AtomicReference<>();
PushPromiseDecoder(int parentStreamId, int pushPromiseStreamId, Stream<?> parent) {
this.parentStreamId = parentStreamId;
this.pushPromiseStreamId = pushPromiseStreamId;
this.parent = parent;
}
@Override
protected void addHeader(String name, String value) {
if (errorRef.get() == null) {
super.addHeader(name, value);
}
}
@Override
public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException {
try {
DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize);
} catch (ProtocolException pe) {
if (parent != null) {
if (errorRef.compareAndSet(null, pe)) {
// cancel the parent stream
resetStream(pushPromiseStreamId, ResetFrame.REFUSED_STREAM);
parent.onProtocolError(pe);
}
} else {
// interrupt decoding and closes the connection
throw pe;
}
}
}
}
volatile boolean closed;
//-------------------------------------
@@ -263,6 +317,7 @@ class Http2Connection {
private final Decoder hpackIn;
final SettingsFrame clientSettings;
private volatile SettingsFrame serverSettings;
private volatile PushContinuationState pushContinuationState;
private final String key; // for HttpClientImpl.connections map
private final FramesDecoder framesDecoder;
private final FramesEncoder framesEncoder = new FramesEncoder();
@@ -275,11 +330,24 @@ class Http2Connection {
private final FramesController framesController = new FramesController();
private final Http2TubeSubscriber subscriber;
final ConnectionWindowUpdateSender windowUpdater;
private volatile Throwable cause;
private final AtomicReference<Throwable> cause = new AtomicReference<>();
private volatile Supplier<ByteBuffer> initial;
private volatile Stream<?> initialStream;
private ValidatingHeadersConsumer orphanedConsumer;
private final AtomicInteger orphanedHeaders = new AtomicInteger();
static final int DEFAULT_FRAME_SIZE = 16 * 1024;
static final int MAX_LITERAL_WITH_INDEXING =
Utils.getIntegerNetProperty("jdk.httpclient.maxLiteralWithIndexing",512);
// The maximum number of HEADER frames, CONTINUATION frames, or PUSH_PROMISE frames
// referring to an already closed or non-existent stream that a client will accept to
// process. Receiving frames referring to non-existent or closed streams doesn't necessarily
// constitute an HTTP/2 protocol error, but receiving too many may indicate a problem
// with the connection. If this limit is reached, a {@link java.net.ProtocolException
// ProtocolException} will be raised and the connection will be closed.
static final int MAX_ORPHANED_HEADERS = 1024;
// TODO: need list of control frames from other threads
// that need to be sent
@@ -287,19 +355,21 @@ class Http2Connection {
private Http2Connection(HttpConnection connection,
Http2ClientImpl client2,
int nextstreamid,
String key) {
String key,
boolean defaultServerPush) {
this.connection = connection;
this.client2 = client2;
this.subscriber = new Http2TubeSubscriber(client2.client());
this.nextstreamid = nextstreamid;
this.key = key;
this.clientSettings = this.client2.getClientSettings();
this.clientSettings = this.client2.getClientSettings(defaultServerPush);
this.framesDecoder = new FramesDecoder(this::processFrame,
clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE));
// serverSettings will be updated by server
this.serverSettings = SettingsFrame.defaultRFCSettings();
this.hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE));
this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE),
clientSettings.getParameter(MAX_HEADER_LIST_SIZE), MAX_LITERAL_WITH_INDEXING);
if (debugHpack.on()) {
debugHpack.log("For the record:" + super.toString());
debugHpack.log("Decoder created: %s", hpackIn);
@@ -318,18 +388,21 @@ class Http2Connection {
private Http2Connection(HttpConnection connection,
Http2ClientImpl client2,
Exchange<?> exchange,
Supplier<ByteBuffer> initial)
Supplier<ByteBuffer> initial,
boolean defaultServerPush)
throws IOException, InterruptedException
{
this(connection,
client2,
3, // stream 1 is registered during the upgrade
keyFor(connection));
reserveStream(true);
keyFor(connection),
defaultServerPush);
reserveStream(true, clientSettings.getFlag(ENABLE_PUSH));
Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize());
Stream<?> initialStream = createStream(exchange);
boolean opened = initialStream.registerStream(1, true);
this.initialStream = initialStream;
if (debug.on() && !opened) {
debug.log("Initial stream was cancelled - but connection is maintained: " +
"reset frame will need to be sent later");
@@ -357,7 +430,8 @@ class Http2Connection {
Exchange<?> exchange,
Supplier<ByteBuffer> initial)
{
return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial));
return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial,
exchange.pushEnabled()));
}
// Requires TLS handshake. So, is really async
@@ -381,7 +455,8 @@ class Http2Connection {
.thenCompose(notused-> {
CompletableFuture<Http2Connection> cf = new MinimalFuture<>();
try {
Http2Connection hc = new Http2Connection(request, h2client, connection);
Http2Connection hc = new Http2Connection(request, h2client,
connection, exchange.pushEnabled());
cf.complete(hc);
} catch (IOException e) {
cf.completeExceptionally(e);
@@ -396,13 +471,15 @@ class Http2Connection {
*/
private Http2Connection(HttpRequestImpl request,
Http2ClientImpl h2client,
HttpConnection connection)
HttpConnection connection,
boolean defaultServerPush)
throws IOException
{
this(connection,
h2client,
1,
keyFor(request));
keyFor(request),
defaultServerPush);
Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize());
@@ -425,15 +502,21 @@ class Http2Connection {
// if false returned then a new Http2Connection is required
// if true, the the stream may be assigned to this connection
// for server push, if false returned, then the stream should be cancelled
synchronized boolean reserveStream(boolean clientInitiated) throws IOException {
synchronized boolean reserveStream(boolean clientInitiated, boolean pushEnabled) throws IOException {
if (finalStream) {
return false;
}
if (clientInitiated && (lastReservedClientStreamid + 2) >= MAX_CLIENT_STREAM_ID) {
// If requesting to reserve a stream for an exchange for which push is enabled,
// we will reserve the stream in this connection only if this connection is also
// push enabled, unless pushes are globally disabled.
boolean pushCompatible = !clientInitiated || !pushEnabled
|| this.serverPushEnabled()
|| client2.serverPushDisabled();
if (clientInitiated && (lastReservedClientStreamid >= MAX_CLIENT_STREAM_ID -2 || !pushCompatible)) {
setFinalStream();
client2.deleteConnection(this);
return false;
} else if (!clientInitiated && (lastReservedServerStreamid + 2) >= MAX_SERVER_STREAM_ID) {
} else if (!clientInitiated && (lastReservedServerStreamid >= MAX_SERVER_STREAM_ID - 2)) {
setFinalStream();
client2.deleteConnection(this);
return false;
@@ -458,6 +541,10 @@ class Http2Connection {
return true;
}
synchronized boolean shouldClose() {
return finalStream() && streams.isEmpty();
}
/**
* Throws an IOException if h2 was not negotiated
*/
@@ -580,6 +667,10 @@ class Http2Connection {
return this.key;
}
public boolean serverPushEnabled() {
return clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1;
}
boolean offerConnection() {
return client2.offerConnection(this);
}
@@ -678,7 +769,7 @@ class Http2Connection {
}
Throwable getRecordedCause() {
return cause;
return cause.get();
}
void shutdown(Throwable t) {
@@ -688,6 +779,7 @@ class Http2Connection {
if (closed == true) return;
closed = true;
}
cause.compareAndSet(null, t);
if (Log.errors()) {
if (!(t instanceof EOFException) || isActive()) {
Log.logError(t);
@@ -695,9 +787,8 @@ class Http2Connection {
Log.logError("Shutting down connection: {0}", t.getMessage());
}
}
Throwable initialCause = this.cause;
if (initialCause == null) this.cause = t;
client2.deleteConnection(this);
subscriber.stop(cause.get());
List<Stream<?>> c = new LinkedList<>(streams.values());
for (Stream<?> s : c) {
try {
@@ -752,17 +843,39 @@ class Http2Connection {
return;
}
if (frame instanceof PushPromiseFrame && !serverPushEnabled()) {
String protocolError = "received a PUSH_PROMISE when SETTINGS_ENABLE_PUSH is 0";
protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
return;
}
Stream<?> stream = getStream(streamid);
if (stream == null) {
var nextstreamid = this.nextstreamid;
if (stream == null && (streamid & 0x01) == 0x01 && streamid >= nextstreamid) {
String protocolError = String.format(
"received a frame for a non existing streamid(%s) >= nextstreamid(%s)",
streamid, nextstreamid);
protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
return;
}
if (stream == null && pushContinuationState == null) {
// Should never receive a frame with unknown stream id
if (frame instanceof HeaderFrame) {
String protocolError = checkMaxOrphanedHeadersExceeded((HeaderFrame)frame);
if (protocolError != null) {
protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
return;
}
// always decode the headers as they may affect
// connection-level HPACK decoding state
DecodingCallback decoder = new ValidatingHeadersConsumer();
if (orphanedConsumer == null || frame.getClass() != ContinuationFrame.class) {
orphanedConsumer = new ValidatingHeadersConsumer();
}
DecodingCallback decoder = orphanedConsumer::onDecoded;
try {
decodeHeaders((HeaderFrame) frame, decoder);
} catch (UncheckedIOException e) {
decodeHeaders((HeaderFrame)frame, decoder);
} catch (IOException | UncheckedIOException e) {
protocolError(ResetFrame.PROTOCOL_ERROR, e.getMessage());
return;
}
@@ -787,29 +900,75 @@ class Http2Connection {
}
return;
}
if (frame instanceof PushPromiseFrame) {
PushPromiseFrame pp = (PushPromiseFrame)frame;
try {
handlePushPromise(stream, pp);
} catch (UncheckedIOException e) {
protocolError(ResetFrame.PROTOCOL_ERROR, e.getMessage());
// While push frame is not null, the only acceptable frame on this
// stream is a Continuation frame
PushContinuationState pcs = pushContinuationState;
if (pcs != null) {
if (frame instanceof ContinuationFrame) {
ContinuationFrame cf = (ContinuationFrame)frame;
if (stream == null) {
String protocolError = checkMaxOrphanedHeadersExceeded(cf);
if (protocolError != null) {
protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
return;
}
}
try {
if (streamid == pcs.pushContFrame.streamid())
handlePushContinuation(pcs, stream, cf);
else {
String protocolError = "Received a CONTINUATION with " +
"unexpected stream id: " + streamid + " != "
+ pcs.pushContFrame.streamid();
protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError);
}
} catch (IOException | UncheckedIOException e) {
debug.log("Error handling Push Promise with Continuation: " + e.getMessage(), e);
protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage());
return;
}
} else {
pushContinuationState = null;
String protocolError = "Expected a CONTINUATION frame but received " + frame;
protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError);
return;
}
} else if (frame instanceof HeaderFrame) {
// decode headers (or continuation)
try {
decodeHeaders((HeaderFrame) frame, stream.rspHeadersConsumer());
} catch (UncheckedIOException e) {
protocolError(ResetFrame.PROTOCOL_ERROR, e.getMessage());
return;
}
stream.incoming(frame);
} else {
stream.incoming(frame);
if (frame instanceof PushPromiseFrame) {
try {
handlePushPromise(stream, (PushPromiseFrame)frame);
} catch (IOException | UncheckedIOException e) {
protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage());
return;
}
} else if (frame instanceof HeaderFrame) {
// decode headers
try {
decodeHeaders((HeaderFrame)frame, stream.rspHeadersConsumer());
} catch (IOException | UncheckedIOException e) {
debug.log("Error decoding headers: " + e.getMessage(), e);
protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage());
return;
}
stream.incoming(frame);
} else {
stream.incoming(frame);
}
}
}
}
private String checkMaxOrphanedHeadersExceeded(HeaderFrame hf) {
if (MAX_ORPHANED_HEADERS > 0 ) {
int orphaned = orphanedHeaders.incrementAndGet();
if (orphaned < 0 || orphaned > MAX_ORPHANED_HEADERS) {
return "Too many orphaned header frames received on connection";
}
}
return null;
}
final void dropDataFrame(DataFrame df) {
if (closed) return;
if (debug.on()) {
@@ -834,24 +993,71 @@ class Http2Connection {
private <T> void handlePushPromise(Stream<T> parent, PushPromiseFrame pp)
throws IOException
{
int promisedStreamid = pp.getPromisedStream();
if ((promisedStreamid & 0x01) != 0x00) {
throw new ProtocolException("Received PUSH_PROMISE for stream " + promisedStreamid);
}
int streamId = pp.streamid();
if ((streamId & 0x01) != 0x01) {
throw new ProtocolException("Received PUSH_PROMISE on stream " + streamId);
}
// always decode the headers as they may affect connection-level HPACK
// decoding state
HeaderDecoder decoder = new HeaderDecoder();
assert pushContinuationState == null;
PushPromiseDecoder decoder = new PushPromiseDecoder(streamId, promisedStreamid, parent);
decodeHeaders(pp, decoder);
if (pp.endHeaders()) {
if (decoder.errorRef.get() == null) {
completePushPromise(promisedStreamid, parent, decoder.headers());
}
} else {
pushContinuationState = new PushContinuationState(decoder, pp);
}
}
private <T> void handlePushContinuation(PushContinuationState pcs, Stream<T> parent, ContinuationFrame cf)
throws IOException {
assert pcs.pushContFrame.streamid() == cf.streamid() : String.format(
"Received CONTINUATION on a different stream %s != %s",
cf.streamid(), pcs.pushContFrame.streamid());
decodeHeaders(cf, pcs.pushContDecoder);
// if all continuations are sent, set pushWithContinuation to null
if (cf.endHeaders()) {
if (pcs.pushContDecoder.errorRef.get() == null) {
completePushPromise(pcs.pushContFrame.getPromisedStream(), parent,
pcs.pushContDecoder.headers());
}
pushContinuationState = null;
}
}
private <T> void completePushPromise(int promisedStreamid, Stream<T> parent, HttpHeaders headers)
throws IOException {
if (parent == null) {
resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM);
return;
}
HttpRequestImpl parentReq = parent.request;
int promisedStreamid = pp.getPromisedStream();
if (promisedStreamid < nextPushStream) {
// From RFC 9113 section 5.1.1:
// The identifier of a newly established stream MUST be numerically
// greater than all streams that the initiating endpoint has
// opened or reserved.
protocolError(ResetFrame.PROTOCOL_ERROR, String.format(
"Unexpected stream identifier: %s < %s", promisedStreamid, nextPushStream));
return;
}
if (promisedStreamid != nextPushStream) {
// we don't support skipping stream ids;
resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR);
return;
} else if (!reserveStream(false)) {
} else if (!reserveStream(false, true)) {
resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM);
return;
} else {
nextPushStream += 2;
}
HttpHeaders headers = decoder.headers();
HttpRequestImpl pushReq = HttpRequestImpl.createPushRequest(parentReq, headers);
Exchange<T> pushExch = new Exchange<>(pushReq, parent.exchange.multi);
Stream.PushedStream<T> pushStream = createPushStream(parent, pushExch);
@@ -974,9 +1180,15 @@ class Http2Connection {
private void protocolError(int errorCode, String msg)
throws IOException
{
String protocolError = "protocol error" + (msg == null?"":(": " + msg));
ProtocolException protocolException =
new ProtocolException(protocolError);
framesDecoder.close(protocolError);
subscriber.stop(protocolException);
if (debug.on()) debug.log("Sending GOAWAY due to " + protocolException);
GoAwayFrame frame = new GoAwayFrame(0, errorCode);
sendFrame(frame);
shutdown(new IOException("protocol error" + (msg == null?"":(": " + msg))));
shutdown(protocolException);
}
private void handleSettings(SettingsFrame frame)
@@ -1083,6 +1295,21 @@ class Http2Connection {
subscriber.onNext(List.of(EMPTY_TRIGGER));
}
/**
* Called to get the initial stream after a connection upgrade.
* If the stream was cancelled, it might no longer be in the
* stream map. Therefore - we use the initialStream field
* instead, and reset it to null after returning it.
* @param <T> the response type
* @return the initial stream created during the upgrade.
*/
@SuppressWarnings("unchecked")
<T> Stream<T> getInitialStream() {
var s = (Stream<T>) initialStream;
initialStream = null;
return s;
}
/**
* Returns an existing Stream with given id, or null if doesn't exist
*/
@@ -1101,7 +1328,7 @@ class Http2Connection {
<T> Stream.PushedStream<T> createPushStream(Stream<T> parent, Exchange<T> pushEx) {
PushGroup<T> pg = parent.exchange.getPushGroup();
return new Stream.PushedStream<>(pg, this, pushEx);
return new Stream.PushedStream<>(parent, pg, this, pushEx);
}
<T> void putStream(Stream<T> stream, int streamid) {
@@ -1163,16 +1390,18 @@ class Http2Connection {
private List<ByteBuffer> encodeHeadersImpl(int bufferSize, HttpHeaders... headers) {
ByteBuffer buffer = getHeaderBuffer(bufferSize);
List<ByteBuffer> buffers = new ArrayList<>();
for(HttpHeaders header : headers) {
for (HttpHeaders header : headers) {
for (Map.Entry<String, List<String>> e : header.map().entrySet()) {
String lKey = e.getKey().toLowerCase(Locale.US);
List<String> values = e.getValue();
for (String value : values) {
hpackOut.header(lKey, value);
while (!hpackOut.encode(buffer)) {
buffer.flip();
buffers.add(buffer);
buffer = getHeaderBuffer(bufferSize);
if (!buffer.hasRemaining()) {
buffer.flip();
buffers.add(buffer);
buffer = getHeaderBuffer(bufferSize);
}
}
}
}
@@ -1235,6 +1464,8 @@ class Http2Connection {
Stream<?> stream = registerNewStream(oh);
// provide protection from inserting unordered frames between Headers and Continuation
if (stream != null) {
// we are creating a new stream: reset orphaned header count
orphanedHeaders.set(0);
publisher.enqueue(encodeHeaders(oh, stream));
}
} else {
@@ -1293,7 +1524,7 @@ class Http2Connection {
private volatile Flow.Subscription subscription;
private volatile boolean completed;
private volatile boolean dropped;
private volatile Throwable error;
private final AtomicReference<Throwable> errorRef = new AtomicReference<>();
private final ConcurrentLinkedQueue<ByteBuffer> queue
= new ConcurrentLinkedQueue<>();
private final SequentialScheduler scheduler =
@@ -1314,10 +1545,9 @@ class Http2Connection {
asyncReceive(buffer);
}
} catch (Throwable t) {
Throwable x = error;
if (x == null) error = t;
errorRef.compareAndSet(null, t);
} finally {
Throwable x = error;
Throwable x = errorRef.get();
if (x != null) {
if (debug.on()) debug.log("Stopping scheduler", x);
scheduler.stop();
@@ -1352,6 +1582,7 @@ class Http2Connection {
@Override
public void onNext(List<ByteBuffer> item) {
if (completed) return;
if (debug.on()) debug.log(() -> "onNext: got " + Utils.remaining(item)
+ " bytes in " + item.size() + " buffers");
queue.addAll(item);
@@ -1360,19 +1591,21 @@ class Http2Connection {
@Override
public void onError(Throwable throwable) {
if (completed) return;
if (debug.on()) debug.log(() -> "onError: " + throwable);
error = throwable;
errorRef.compareAndSet(null, throwable);
completed = true;
runOrSchedule();
}
@Override
public void onComplete() {
if (completed) return;
String msg = isActive()
? "EOF reached while reading"
: "Idle connection closed by HTTP/2 peer";
if (debug.on()) debug.log(msg);
error = new EOFException(msg);
errorRef.compareAndSet(null, new EOFException(msg));
completed = true;
runOrSchedule();
}
@@ -1384,6 +1617,18 @@ class Http2Connection {
// then we might not need the 'dropped' boolean?
dropped = true;
}
void stop(Throwable error) {
if (errorRef.compareAndSet(null, error)) {
completed = true;
scheduler.stop();
queue.clear();
if (subscription != null) {
subscription.cancel();
}
queue.clear();
}
}
}
synchronized boolean isActive() {
@@ -1400,76 +1645,6 @@ class Http2Connection {
+ connection.getConnectionFlow() + ")";
}
static class HeaderDecoder extends ValidatingHeadersConsumer {
HttpHeadersBuilder headersBuilder;
HeaderDecoder() {
this.headersBuilder = new HttpHeadersBuilder();
}
@Override
public void onDecoded(CharSequence name, CharSequence value) {
String n = name.toString();
String v = value.toString();
super.onDecoded(n, v);
headersBuilder.addHeader(n, v);
}
HttpHeaders headers() {
return headersBuilder.build();
}
}
/*
* Checks RFC 7540 rules (relaxed) compliance regarding pseudo-headers.
*/
static class ValidatingHeadersConsumer implements DecodingCallback {
private static final Set<String> PSEUDO_HEADERS =
Set.of(":authority", ":method", ":path", ":scheme", ":status");
/** Used to check that if there are pseudo-headers, they go first */
private boolean pseudoHeadersEnded;
/**
* Called when END_HEADERS was received. This consumer may be invoked
* again after reset() is called, but for a whole new set of headers.
*/
void reset() {
pseudoHeadersEnded = false;
}
@Override
public void onDecoded(CharSequence name, CharSequence value)
throws UncheckedIOException
{
String n = name.toString();
if (n.startsWith(":")) {
if (pseudoHeadersEnded) {
throw newException("Unexpected pseudo-header '%s'", n);
} else if (!PSEUDO_HEADERS.contains(n)) {
throw newException("Unknown pseudo-header '%s'", n);
}
} else {
pseudoHeadersEnded = true;
if (!Utils.isValidName(n)) {
throw newException("Bad header name '%s'", n);
}
}
String v = value.toString();
if (!Utils.isValidValue(v)) {
throw newException("Bad header value '%s'", v);
}
}
private UncheckedIOException newException(String message, String header)
{
return new UncheckedIOException(
new IOException(String.format(message, header)));
}
}
static final class ConnectionWindowUpdateSender extends WindowUpdateSender {
final int initialWindowSize;

View File

@@ -563,7 +563,9 @@ final class HttpClientImpl extends HttpClient implements Trackable {
ce.initCause(throwable);
throw ce;
} else if (throwable instanceof ProtocolException) {
throw new ProtocolException(msg);
ProtocolException pe = new ProtocolException(msg);
pe.initCause(throwable);
throw pe;
} else if (throwable instanceof IOException) {
throw new IOException(msg, throwable);
} else {

View File

@@ -272,10 +272,10 @@ public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
InetSocketAddress authority() { return authority; }
void setH2Upgrade(Http2ClientImpl h2client) {
void setH2Upgrade(Exchange<?> exchange) {
systemHeadersBuilder.setHeader("Connection", "Upgrade, HTTP2-Settings");
systemHeadersBuilder.setHeader("Upgrade", "h2c");
systemHeadersBuilder.setHeader("HTTP2-Settings", h2client.getSettingsString());
systemHeadersBuilder.setHeader("HTTP2-Settings", exchange.h2cSettingsStrings());
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@@ -35,6 +35,7 @@ import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@@ -123,16 +124,21 @@ public final class ResponseBodyHandlers {
if (!initiatingURI.getHost().equalsIgnoreCase(pushRequestURI.getHost()))
return;
String initiatingScheme = initiatingURI.getScheme();
String pushRequestScheme = pushRequestURI.getScheme();
if (!initiatingScheme.equalsIgnoreCase(pushRequestScheme)) return;
int initiatingPort = initiatingURI.getPort();
if (initiatingPort == -1 ) {
if ("https".equalsIgnoreCase(initiatingURI.getScheme()))
if ("https".equalsIgnoreCase(initiatingScheme))
initiatingPort = 443;
else
initiatingPort = 80;
}
int pushPort = pushRequestURI.getPort();
if (pushPort == -1 ) {
if ("https".equalsIgnoreCase(pushRequestURI.getScheme()))
if ("https".equalsIgnoreCase(pushRequestScheme))
pushPort = 443;
else
pushPort = 80;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023, 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
@@ -30,6 +30,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.net.ProtocolException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -42,6 +43,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Flow;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiPredicate;
import java.net.http.HttpClient;
@@ -49,10 +51,13 @@ import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodySubscriber;
import jdk.internal.net.http.common.*;
import jdk.internal.net.http.frame.*;
import jdk.internal.net.http.hpack.DecodingCallback;
import static jdk.internal.net.http.Exchange.MAX_NON_FINAL_RESPONSES;
/**
* Http/2 Stream handling.
*
@@ -136,6 +141,10 @@ class Stream<T> extends ExchangeImpl<T> {
private volatile boolean remotelyClosed;
private volatile boolean closed;
private volatile boolean endStreamSent;
private volatile boolean finalResponseCodeReceived;
private volatile boolean trailerReceived;
private AtomicInteger nonFinalResponseCount = new AtomicInteger();
// Indicates the first reason that was invoked when sending a ResetFrame
// to the server. A streamState of 0 indicates that no reset was sent.
// (see markStream(int code)
@@ -472,32 +481,89 @@ class Stream<T> extends ExchangeImpl<T> {
return rspHeadersConsumer;
}
String checkInterimResponseCountExceeded() {
// this is also checked by Exchange - but tracking it here too provides
// a more informative message.
int count = nonFinalResponseCount.incrementAndGet();
if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) {
return String.format(
"Stream %s PROTOCOL_ERROR: too many interim responses received: %s > %s",
streamid, count, MAX_NON_FINAL_RESPONSES);
}
return null;
}
protected void handleResponse() throws IOException {
HttpHeaders responseHeaders = responseHeadersBuilder.build();
responseCode = (int)responseHeaders
.firstValueAsLong(":status")
.orElseThrow(() -> new IOException("no statuscode in response"));
response = new Response(
request, exchange, responseHeaders, connection(),
responseCode, HttpClient.Version.HTTP_2);
if (!finalResponseCodeReceived) {
try {
responseCode = (int) responseHeaders
.firstValueAsLong(":status")
.orElseThrow(() -> new ProtocolException(String.format(
"Stream %s PROTOCOL_ERROR: no status code in response",
streamid)));
} catch (ProtocolException cause) {
cancelImpl(cause, ResetFrame.PROTOCOL_ERROR);
rspHeadersConsumer.reset();
return;
}
/* TODO: review if needs to be removed
the value is not used, but in case `content-length` doesn't parse as
long, there will be NumberFormatException. If left as is, make sure
code up the stack handles NFE correctly. */
responseHeaders.firstValueAsLong("content-length");
String protocolErrorMsg = null;
// If informational code, response is partially complete
if (responseCode < 100 || responseCode > 199) {
this.finalResponseCodeReceived = true;
} else {
protocolErrorMsg = checkInterimResponseCountExceeded();
}
if (Log.headers()) {
StringBuilder sb = new StringBuilder("RESPONSE HEADERS:\n");
Log.dumpHeaders(sb, " ", responseHeaders);
Log.logHeaders(sb.toString());
if (protocolErrorMsg != null) {
if (debug.on()) {
debug.log(protocolErrorMsg);
}
cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR);
rspHeadersConsumer.reset();
return;
}
response = new Response(
request, exchange, responseHeaders, connection(),
responseCode, HttpClient.Version.HTTP_2);
/* TODO: review if needs to be removed
the value is not used, but in case `content-length` doesn't parse as
long, there will be NumberFormatException. If left as is, make sure
code up the stack handles NFE correctly. */
responseHeaders.firstValueAsLong("content-length");
if (Log.headers()) {
StringBuilder sb = new StringBuilder("RESPONSE HEADERS:\n");
Log.dumpHeaders(sb, " ", responseHeaders);
Log.logHeaders(sb.toString());
}
// this will clear the response headers
rspHeadersConsumer.reset();
completeResponse(response);
} else {
if (Log.headers()) {
StringBuilder sb = new StringBuilder("TRAILING HEADERS:\n");
Log.dumpHeaders(sb, " ", responseHeaders);
Log.logHeaders(sb.toString());
}
if (trailerReceived) {
String protocolErrorMsg = String.format(
"Stream %s PROTOCOL_ERROR: trailers already received", streamid);
if (debug.on()) {
debug.log(protocolErrorMsg);
}
cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR);
}
trailerReceived = true;
rspHeadersConsumer.reset();
}
// this will clear the response headers
rspHeadersConsumer.reset();
completeResponse(response);
}
void incoming_reset(ResetFrame frame) {
@@ -1052,7 +1118,7 @@ class Stream<T> extends ExchangeImpl<T> {
/**
* A List of responses relating to this stream. Normally there is only
* one response, but intermediate responses like 100 are allowed
* one response, but interim responses like 100 are allowed
* and must be passed up to higher level before continuing. Deals with races
* such as if responses are returned before the CFs get created by
* getResponseAsync()
@@ -1237,7 +1303,7 @@ class Stream<T> extends ExchangeImpl<T> {
cancelImpl(e, ResetFrame.CANCEL);
}
private void cancelImpl(final Throwable e, final int resetFrameErrCode) {
void cancelImpl(final Throwable e, final int resetFrameErrCode) {
errorRef.compareAndSet(null, e);
if (debug.on()) {
if (streamid == 0) debug.log("cancelling stream: %s", (Object)e);
@@ -1306,6 +1372,7 @@ class Stream<T> extends ExchangeImpl<T> {
}
static class PushedStream<T> extends Stream<T> {
final Stream<T> parent;
final PushGroup<T> pushGroup;
// push streams need the response CF allocated up front as it is
// given directly to user via the multi handler callback function.
@@ -1313,17 +1380,19 @@ class Stream<T> extends ExchangeImpl<T> {
CompletableFuture<HttpResponse<T>> responseCF;
final HttpRequestImpl pushReq;
HttpResponse.BodyHandler<T> pushHandler;
private volatile boolean finalPushResponseCodeReceived;
PushedStream(PushGroup<T> pushGroup,
PushedStream(Stream<T> parent,
PushGroup<T> pushGroup,
Http2Connection connection,
Exchange<T> pushReq) {
// ## no request body possible, null window controller
super(connection, pushReq, null);
this.parent = parent;
this.pushGroup = pushGroup;
this.pushReq = pushReq.request();
this.pushCF = new MinimalFuture<>();
this.responseCF = new MinimalFuture<>();
}
CompletableFuture<HttpResponse<T>> responseCF() {
@@ -1409,35 +1478,57 @@ class Stream<T> extends ExchangeImpl<T> {
@Override
protected void handleResponse() {
HttpHeaders responseHeaders = responseHeadersBuilder.build();
responseCode = (int)responseHeaders
.firstValueAsLong(":status")
.orElse(-1);
if (responseCode == -1) {
completeResponseExceptionally(new IOException("No status code"));
if (!finalPushResponseCodeReceived) {
responseCode = (int)responseHeaders
.firstValueAsLong(":status")
.orElse(-1);
if (responseCode == -1) {
cancelImpl(new ProtocolException("No status code"), ResetFrame.PROTOCOL_ERROR);
rspHeadersConsumer.reset();
return;
} else if (responseCode >= 100 && responseCode < 200) {
String protocolErrorMsg = checkInterimResponseCountExceeded();
if (protocolErrorMsg != null) {
cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR);
rspHeadersConsumer.reset();
return;
}
}
this.finalPushResponseCodeReceived = true;
this.response = new Response(
pushReq, exchange, responseHeaders, connection(),
responseCode, HttpClient.Version.HTTP_2);
/* TODO: review if needs to be removed
the value is not used, but in case `content-length` doesn't parse
as long, there will be NumberFormatException. If left as is, make
sure code up the stack handles NFE correctly. */
responseHeaders.firstValueAsLong("content-length");
if (Log.headers()) {
StringBuilder sb = new StringBuilder("RESPONSE HEADERS");
sb.append(" (streamid=").append(streamid).append("):\n");
Log.dumpHeaders(sb, " ", responseHeaders);
Log.logHeaders(sb.toString());
}
rspHeadersConsumer.reset();
// different implementations for normal streams and pushed streams
completeResponse(response);
} else {
if (Log.headers()) {
StringBuilder sb = new StringBuilder("TRAILING HEADERS");
sb.append(" (streamid=").append(streamid).append("):\n");
Log.dumpHeaders(sb, " ", responseHeaders);
Log.logHeaders(sb.toString());
}
rspHeadersConsumer.reset();
}
this.response = new Response(
pushReq, exchange, responseHeaders, connection(),
responseCode, HttpClient.Version.HTTP_2);
/* TODO: review if needs to be removed
the value is not used, but in case `content-length` doesn't parse
as long, there will be NumberFormatException. If left as is, make
sure code up the stack handles NFE correctly. */
responseHeaders.firstValueAsLong("content-length");
if (Log.headers()) {
StringBuilder sb = new StringBuilder("RESPONSE HEADERS");
sb.append(" (streamid=").append(streamid).append("):\n");
Log.dumpHeaders(sb, " ", responseHeaders);
Log.logHeaders(sb.toString());
}
rspHeadersConsumer.reset();
// different implementations for normal streams and pushed streams
completeResponse(response);
}
}
@@ -1485,9 +1576,12 @@ class Stream<T> extends ExchangeImpl<T> {
return connection.dbgString() + "/Stream("+streamid+")";
}
private class HeadersConsumer extends Http2Connection.ValidatingHeadersConsumer {
private class HeadersConsumer extends ValidatingHeadersConsumer implements DecodingCallback {
void reset() {
boolean maxHeaderListSizeReached;
@Override
public void reset() {
super.reset();
responseHeadersBuilder.clear();
debug.log("Response builder cleared, ready to receive new headers.");
@@ -1497,13 +1591,46 @@ class Stream<T> extends ExchangeImpl<T> {
public void onDecoded(CharSequence name, CharSequence value)
throws UncheckedIOException
{
String n = name.toString();
String v = value.toString();
super.onDecoded(n, v);
responseHeadersBuilder.addHeader(n, v);
if (Log.headers() && Log.trace()) {
Log.logTrace("RECEIVED HEADER (streamid={0}): {1}: {2}",
streamid, n, v);
if (maxHeaderListSizeReached) {
return;
}
try {
String n = name.toString();
String v = value.toString();
super.onDecoded(n, v);
responseHeadersBuilder.addHeader(n, v);
if (Log.headers() && Log.trace()) {
Log.logTrace("RECEIVED HEADER (streamid={0}): {1}: {2}",
streamid, n, v);
}
} catch (UncheckedIOException uio) {
// reset stream: From RFC 9113, section 8.1
// Malformed requests or responses that are detected MUST be
// treated as a stream error (Section 5.4.2) of type
// PROTOCOL_ERROR.
onProtocolError(uio.getCause());
}
}
@Override
protected String formatMessage(String message, String header) {
return "malformed response: " + super.formatMessage(message, header);
}
@Override
public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException {
if (maxHeaderListSizeReached) return;
try {
DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize);
} catch (ProtocolException cause) {
maxHeaderListSizeReached = true;
// If this is a push stream: cancel the parent.
if (Stream.this instanceof Stream.PushedStream<?>) {
((Stream.PushedStream<?>)Stream.this).parent.onProtocolError(cause);
}
// cancel the stream, continue processing
onProtocolError(cause);
reset();
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2023, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.internal.net.http.common;
import java.net.http.HttpHeaders;
public class HeaderDecoder extends ValidatingHeadersConsumer {
private final HttpHeadersBuilder headersBuilder;
public HeaderDecoder() {
this.headersBuilder = new HttpHeadersBuilder();
}
@Override
public void onDecoded(CharSequence name, CharSequence value) {
String n = name.toString();
String v = value.toString();
super.onDecoded(n, v);
addHeader(n, v);
}
protected void addHeader(String name, String value) {
headersBuilder.addHeader(name, value);
}
public HttpHeaders headers() {
return headersBuilder.build();
}
}

View File

@@ -371,16 +371,21 @@ public final class Utils {
}
private static final boolean[] LOWER_CASE_CHARS = new boolean[128];
// ABNF primitives defined in RFC 7230
private static final boolean[] tchar = new boolean[256];
private static final boolean[] fieldvchar = new boolean[256];
static {
char[] allowedTokenChars =
("!#$%&'*+-.^_`|~0123456789" +
"abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
for (char c : allowedTokenChars) {
char[] lcase = ("!#$%&'*+-.^_`|~0123456789" +
"abcdefghijklmnopqrstuvwxyz").toCharArray();
for (char c : lcase) {
tchar[c] = true;
LOWER_CASE_CHARS[c] = true;
}
char[] ucase = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
for (char c : ucase) {
tchar[c] = true;
}
for (char c = 0x21; c < 0xFF; c++) {
@@ -389,6 +394,16 @@ public final class Utils {
fieldvchar[0x7F] = false; // a little hole (DEL) in the range
}
public static boolean isValidLowerCaseName(String token) {
for (int i = 0; i < token.length(); i++) {
char c = token.charAt(i);
if (c > 255 || !LOWER_CASE_CHARS[c]) {
return false;
}
}
return !token.isEmpty();
}
/*
* Validates a RFC 7230 field-name.
*/
@@ -500,6 +515,19 @@ public final class Utils {
Integer.parseInt(System.getProperty(name, String.valueOf(defaultValue))));
}
public static int getIntegerNetProperty(String property, int min, int max, int defaultValue, boolean log) {
int value = Utils.getIntegerNetProperty(property, defaultValue);
// use default value if misconfigured
if (value < min || value > max) {
if (log && Log.errors()) {
Log.logError("Property value for {0}={1} not in [{2}..{3}]: " +
"using default={4}", property, value, min, max, defaultValue);
}
value = defaultValue;
}
return value;
}
public static SSLParameters copySSLParameters(SSLParameters p) {
SSLParameters p1 = new SSLParameters();
p1.setAlgorithmConstraints(p.getAlgorithmConstraints());

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2023, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.internal.net.http.common;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Set;
/*
* Checks RFC 9113 rules (relaxed) compliance regarding pseudo-headers.
*/
public class ValidatingHeadersConsumer {
private static final Set<String> PSEUDO_HEADERS =
Set.of(":authority", ":method", ":path", ":scheme", ":status");
/** Used to check that if there are pseudo-headers, they go first */
private boolean pseudoHeadersEnded;
/**
* Called when END_HEADERS was received. This consumer may be invoked
* again after reset() is called, but for a whole new set of headers.
*/
public void reset() {
pseudoHeadersEnded = false;
}
/**
* Called when a header field (name, value) pair has been decoded
* @param name the decoded name
* @param value the decoded value
* @throws UncheckedIOException if the name or value are illegal
*/
public void onDecoded(CharSequence name, CharSequence value)
throws UncheckedIOException
{
String n = name.toString();
if (n.startsWith(":")) {
if (pseudoHeadersEnded) {
throw newException("Unexpected pseudo-header '%s'", n);
} else if (!PSEUDO_HEADERS.contains(n)) {
throw newException("Unknown pseudo-header '%s'", n);
}
} else {
pseudoHeadersEnded = true;
// RFC-9113, section 8.2.1 for HTTP/2 and RFC-9114, section 4.2 state that
// header name MUST be lowercase (and allowed characters)
if (!Utils.isValidLowerCaseName(n)) {
throw newException("Bad header name '%s'", n);
}
}
String v = value.toString();
if (!Utils.isValidValue(v)) {
throw newException("Bad header value '%s'", v);
}
}
protected String formatMessage(String message, String header) {
return String.format(message, header);
}
protected UncheckedIOException newException(String message, String header)
{
return new UncheckedIOException(
new IOException(formatMessage(message, header)));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2024, 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
@@ -27,6 +27,7 @@ package jdk.internal.net.http.hpack;
import jdk.internal.net.http.hpack.HPACK.Logger;
import java.io.IOException;
import java.net.ProtocolException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@@ -107,12 +108,16 @@ public final class Decoder {
private final StringReader stringReader;
private final StringBuilder name;
private final StringBuilder value;
private final int maxHeaderListSize;
private final int maxIndexed;
private int intValue;
private boolean firstValueRead;
private boolean firstValueIndex;
private boolean nameHuffmanEncoded;
private boolean valueHuffmanEncoded;
private int capacity;
private long size;
private int indexed;
/**
* Constructs a {@code Decoder} with the specified initial capacity of the
@@ -129,6 +134,31 @@ public final class Decoder {
* if capacity is negative
*/
public Decoder(int capacity) {
this(capacity, 0, 0);
}
/**
* Constructs a {@code Decoder} with the specified initial capacity of the
* header table, a max header list size, and a maximum number of literals
* with indexing per header section.
*
* <p> The value of the capacity has to be agreed between decoder and encoder out-of-band,
* e.g. by a protocol that uses HPACK
* (see <a href="https://tools.ietf.org/html/rfc7541#section-4.2">4.2. Maximum Table Size</a>).
*
* @param capacity
* a non-negative integer
* @param maxHeaderListSize
* a maximum value for the header list size. This is the uncompressed
* names size + uncompressed values size + 32 bytes per field line
* @param maxIndexed
* the maximum number of literal with indexing we're prepared to handle
* for a header field section
*
* @throws IllegalArgumentException
* if capacity is negative
*/
public Decoder(int capacity, int maxHeaderListSize, int maxIndexed) {
id = DECODERS_IDS.incrementAndGet();
logger = HPACK.getLogger().subLogger("Decoder#" + id);
if (logger.isLoggable(NORMAL)) {
@@ -145,6 +175,8 @@ public final class Decoder {
toString(), hashCode);
});
}
this.maxHeaderListSize = maxHeaderListSize;
this.maxIndexed = maxIndexed;
setMaxCapacity0(capacity);
table = new SimpleHeaderTable(capacity, logger.subLogger("HeaderTable"));
integerReader = new IntegerReader();
@@ -242,23 +274,26 @@ public final class Decoder {
requireNonNull(consumer, "consumer");
if (logger.isLoggable(NORMAL)) {
logger.log(NORMAL, () -> format("reading %s, end of header block? %s",
headerBlock, endOfHeaderBlock));
headerBlock, endOfHeaderBlock));
}
while (headerBlock.hasRemaining()) {
proceed(headerBlock, consumer);
}
if (endOfHeaderBlock && state != State.READY) {
logger.log(NORMAL, () -> format("unexpected end of %s representation",
state));
state));
throw new IOException("Unexpected end of header block");
}
if (endOfHeaderBlock) {
size = indexed = 0;
}
}
private void proceed(ByteBuffer input, DecodingCallback action)
throws IOException {
switch (state) {
case READY:
resumeReady(input);
resumeReady(input, action);
break;
case INDEXED:
resumeIndexed(input, action);
@@ -280,7 +315,7 @@ public final class Decoder {
}
}
private void resumeReady(ByteBuffer input) {
private void resumeReady(ByteBuffer input, DecodingCallback action) throws IOException {
int b = input.get(input.position()) & 0xff; // absolute read
State s = states.get(b);
if (logger.isLoggable(EXTRA)) {
@@ -301,6 +336,9 @@ public final class Decoder {
}
break;
case LITERAL_WITH_INDEXING:
if (maxIndexed > 0 && ++indexed > maxIndexed) {
action.onMaxLiteralWithIndexingReached(indexed, maxIndexed);
}
state = State.LITERAL_WITH_INDEXING;
firstValueIndex = (b & 0b0011_1111) != 0;
if (firstValueIndex) {
@@ -327,6 +365,12 @@ public final class Decoder {
}
}
private void checkMaxHeaderListSize(long sz, DecodingCallback consumer) throws ProtocolException {
if (maxHeaderListSize > 0 && sz > maxHeaderListSize) {
consumer.onMaxHeaderListSizeReached(sz, maxHeaderListSize);
}
}
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 1 | Index (7+) |
@@ -344,6 +388,8 @@ public final class Decoder {
}
try {
SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
size = size + 32 + f.name.length() + f.value.length();
checkMaxHeaderListSize(size, action);
action.onIndexed(intValue, f.name, f.value);
} finally {
state = State.READY;
@@ -386,7 +432,7 @@ public final class Decoder {
//
private void resumeLiteral(ByteBuffer input, DecodingCallback action)
throws IOException {
if (!completeReading(input)) {
if (!completeReading(input, action)) {
return;
}
try {
@@ -397,6 +443,8 @@ public final class Decoder {
intValue, value, valueHuffmanEncoded));
}
SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
size = size + 32 + f.name.length() + value.length();
checkMaxHeaderListSize(size, action);
action.onLiteral(intValue, f.name, value, valueHuffmanEncoded);
} else {
if (logger.isLoggable(NORMAL)) {
@@ -404,6 +452,8 @@ public final class Decoder {
"literal without indexing ('%s', huffman=%b, '%s', huffman=%b)",
name, nameHuffmanEncoded, value, valueHuffmanEncoded));
}
size = size + 32 + name.length() + value.length();
checkMaxHeaderListSize(size, action);
action.onLiteral(name, nameHuffmanEncoded, value, valueHuffmanEncoded);
}
} finally {
@@ -437,7 +487,7 @@ public final class Decoder {
private void resumeLiteralWithIndexing(ByteBuffer input,
DecodingCallback action)
throws IOException {
if (!completeReading(input)) {
if (!completeReading(input, action)) {
return;
}
try {
@@ -457,6 +507,8 @@ public final class Decoder {
}
SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
n = f.name;
size = size + 32 + n.length() + v.length();
checkMaxHeaderListSize(size, action);
action.onLiteralWithIndexing(intValue, n, v, valueHuffmanEncoded);
} else {
n = name.toString();
@@ -465,6 +517,8 @@ public final class Decoder {
"literal with incremental indexing ('%s', huffman=%b, '%s', huffman=%b)",
n, nameHuffmanEncoded, value, valueHuffmanEncoded));
}
size = size + 32 + n.length() + v.length();
checkMaxHeaderListSize(size, action);
action.onLiteralWithIndexing(n, nameHuffmanEncoded, v, valueHuffmanEncoded);
}
table.put(n, v);
@@ -498,7 +552,7 @@ public final class Decoder {
private void resumeLiteralNeverIndexed(ByteBuffer input,
DecodingCallback action)
throws IOException {
if (!completeReading(input)) {
if (!completeReading(input, action)) {
return;
}
try {
@@ -509,6 +563,8 @@ public final class Decoder {
intValue, value, valueHuffmanEncoded));
}
SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
size = size + 32 + f.name.length() + value.length();
checkMaxHeaderListSize(size, action);
action.onLiteralNeverIndexed(intValue, f.name, value, valueHuffmanEncoded);
} else {
if (logger.isLoggable(NORMAL)) {
@@ -516,6 +572,8 @@ public final class Decoder {
"literal never indexed ('%s', huffman=%b, '%s', huffman=%b)",
name, nameHuffmanEncoded, value, valueHuffmanEncoded));
}
size = size + 32 + name.length() + value.length();
checkMaxHeaderListSize(size, action);
action.onLiteralNeverIndexed(name, nameHuffmanEncoded, value, valueHuffmanEncoded);
}
} finally {
@@ -553,7 +611,7 @@ public final class Decoder {
}
}
private boolean completeReading(ByteBuffer input) throws IOException {
private boolean completeReading(ByteBuffer input, DecodingCallback action) throws IOException {
if (!firstValueRead) {
if (firstValueIndex) {
if (!integerReader.read(input)) {
@@ -563,6 +621,8 @@ public final class Decoder {
integerReader.reset();
} else {
if (!stringReader.read(input, name)) {
long sz = size + 32 + name.length();
checkMaxHeaderListSize(sz, action);
return false;
}
nameHuffmanEncoded = stringReader.isHuffmanEncoded();
@@ -572,6 +632,8 @@ public final class Decoder {
return false;
} else {
if (!stringReader.read(input, value)) {
long sz = size + 32 + name.length() + value.length();
checkMaxHeaderListSize(sz, action);
return false;
}
}

View File

@@ -24,6 +24,7 @@
*/
package jdk.internal.net.http.hpack;
import java.net.ProtocolException;
import java.nio.ByteBuffer;
/**
@@ -292,4 +293,17 @@ public interface DecodingCallback {
* new capacity of the header table
*/
default void onSizeUpdate(int capacity) { }
default void onMaxHeaderListSizeReached(long size, int maxHeaderListSize)
throws ProtocolException {
throw new ProtocolException(String
.format("Size exceeds MAX_HEADERS_LIST_SIZE: %s > %s",
size, maxHeaderListSize));
}
default void onMaxLiteralWithIndexingReached(long indexed, int maxIndexed)
throws ProtocolException {
throw new ProtocolException(String.format("Too many literal with indexing: %s > %s",
indexed, maxIndexed));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2024, 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
@@ -258,9 +258,10 @@ public class Encoder {
}
}
}
assert encoding : "encoding is false";
}
private boolean isHuffmanBetterFor(CharSequence value) {
protected final boolean isHuffmanBetterFor(CharSequence value) {
// prefer Huffman encoding only if it is strictly smaller than Latin-1
return huffmanWriter.lengthOf(value) < value.length();
}
@@ -340,6 +341,10 @@ public class Encoder {
return 0;
}
protected final int tableIndexOf(CharSequence name, CharSequence value) {
return getHeaderTable().indexOf(name, value);
}
/**
* Encodes the {@linkplain #header(CharSequence, CharSequence) set up}
* header into the given buffer.
@@ -380,6 +385,7 @@ public class Encoder {
writer.reset(); // FIXME: WHY?
encoding = false;
}
assert done || encoding : "done: " + done + ", encoding: " + encoding;
return done;
}
@@ -542,4 +548,8 @@ public class Encoder {
"Previous encoding operation hasn't finished yet");
}
}
protected final Logger logger() {
return logger;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2024, 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
@@ -168,7 +168,7 @@ public final class EncryptionKey implements SecretKey {
if (destroyed) {
return "Destroyed EncryptionKey";
}
return "key " + key.toString();
return "EncryptionKey: " + key.toString();
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2024, 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
@@ -27,7 +27,6 @@ package javax.security.auth.kerberos;
import javax.security.auth.Destroyable;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;
/**
@@ -140,8 +139,7 @@ public final class KerberosCredMessage implements Destroyable {
if (destroyed) {
return "Destroyed KerberosCredMessage";
} else {
return "KRB_CRED from " + sender + " to " + recipient + ":\n"
+ Base64.getUrlEncoder().encodeToString(message);
return "KRB_CRED from " + sender + " to " + recipient;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@@ -270,9 +270,9 @@ public class KerberosKey implements SecretKey {
if (destroyed) {
return "Destroyed KerberosKey";
}
return "Kerberos Principal " + principal +
"Key Version " + versionNum +
"key " + key.toString();
return "KerberosKey: principal " + principal +
", version " + versionNum +
", key " + key.toString();
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@@ -30,7 +30,8 @@ import java.util.Arrays;
import javax.crypto.SecretKey;
import javax.security.auth.Destroyable;
import javax.security.auth.DestroyFailedException;
import sun.security.util.HexDumpEncoder;
import sun.security.jgss.krb5.Krb5Util;
import sun.security.krb5.Asn1Exception;
import sun.security.krb5.PrincipalName;
import sun.security.krb5.EncryptionKey;
@@ -210,15 +211,8 @@ class KeyImpl implements SecretKey, Destroyable, Serializable {
}
public String toString() {
HexDumpEncoder hd = new HexDumpEncoder();
return "EncryptionKey: keyType=" + keyType
+ " keyBytes (hex dump)="
+ (keyBytes == null || keyBytes.length == 0 ?
" Empty Key" :
'\n' + hd.encodeBuffer(keyBytes)
+ '\n');
return "keyType=" + keyType
+ ", " + Krb5Util.keyInfo(keyBytes);
}
public int hashCode() {

View File

@@ -909,15 +909,11 @@ class Krb5Context implements GSSContextSpi {
public final byte[] wrap(byte[] inBuf, int offset, int len,
MessageProp msgProp) throws GSSException {
if (DEBUG) {
System.out.println("Krb5Context.wrap: data=["
+ getHexBytes(inBuf, offset, len)
+ "]");
}
if (state != STATE_DONE)
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Wrap called in invalid state!");
if (state != STATE_DONE) {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Wrap called in invalid state!");
}
byte[] encToken = null;
try {
@@ -1062,12 +1058,6 @@ class Krb5Context implements GSSContextSpi {
setSequencingAndReplayProps(token, msgProp);
}
if (DEBUG) {
System.out.println("Krb5Context.unwrap: data=["
+ getHexBytes(data, 0, data.length)
+ "]");
}
return data;
}
@@ -1416,8 +1406,8 @@ class Krb5Context implements GSSContextSpi {
@Override
public String toString() {
return "Kerberos session key: etype: " + key.getEType() + "\n" +
new HexDumpEncoder().encodeBuffer(key.getBytes());
return "Kerberos session key: etype=" + key.getEType()
+ ", " + Krb5Util.keyInfo(key.getBytes());
}
}

View File

@@ -301,4 +301,19 @@ public class Krb5Util {
KeyTab ktab, PrincipalName cname) {
return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname);
}
public static String keyInfo(byte[] data) {
if (data == null) {
return "null key";
} else if (data.length == 0) {
return "empty key";
} else {
for (byte b : data) {
if (b != 0) {
return data.length + "-byte key";
}
}
return data.length + "-byte zero key";
}
}
}

View File

@@ -31,6 +31,7 @@
package sun.security.krb5;
import sun.security.jgss.krb5.Krb5Util;
import sun.security.util.*;
import sun.security.krb5.internal.*;
import sun.security.krb5.internal.crypto.*;
@@ -498,12 +499,7 @@ public class EncryptionKey
public String toString() {
return new String("EncryptionKey: keyType=" + keyType
+ " kvno=" + kvno
+ " keyValue (hex dump)="
+ (keyValue == null || keyValue.length == 0 ?
" Empty Key" : '\n'
+ Krb5.hexDumper.encodeBuffer(keyValue)
+ '\n'));
+ ", kvno=" + kvno + ", " + Krb5Util.keyInfo(keyValue));
}
/**

View File

@@ -313,8 +313,6 @@ public class Krb5 {
public static final boolean DEBUG =
java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
public static final sun.security.util.HexDumpEncoder hexDumper =
new sun.security.util.HexDumpEncoder();
static {
errMsgList = new Hashtable<Integer,String> ();

View File

@@ -192,10 +192,6 @@ public class Kinit {
System.out.print("Password for " + princName + ":");
System.out.flush();
psswd = Password.readPassword(System.in);
if (DEBUG) {
System.out.println(">>> Kinit console input " +
new String(psswd));
}
}
builder = new KrbAsReqBuilder(principal, psswd);
} else {

View File

@@ -121,11 +121,6 @@ public class CK_PBE_PARAMS {
sb.append(pPassword.length);
sb.append(Constants.NEWLINE);
sb.append(Constants.INDENT);
sb.append("pPassword: ");
sb.append(pPassword);
sb.append(Constants.NEWLINE);
sb.append(Constants.INDENT);
sb.append("ulSaltLen: ");
sb.append(pSalt.length);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2024, 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
@@ -42,8 +42,10 @@ class Request {
private SocketChannel chan;
private InputStream is;
private OutputStream os;
private final int maxReqHeaderSize;
Request (InputStream rawInputStream, OutputStream rawout) throws IOException {
this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize();
is = rawInputStream;
os = rawout;
do {
@@ -76,6 +78,7 @@ class Request {
public String readLine () throws IOException {
boolean gotCR = false, gotLF = false;
pos = 0; lineBuf = new StringBuffer();
long lsize = 32;
while (!gotLF) {
int c = is.read();
if (c == -1) {
@@ -88,20 +91,27 @@ class Request {
gotCR = false;
consume (CR);
consume (c);
lsize = lsize + 2;
}
} else {
if (c == CR) {
gotCR = true;
} else {
consume (c);
lsize = lsize + 1;
}
}
if (maxReqHeaderSize > 0 && lsize > maxReqHeaderSize) {
throw new IOException("Maximum header (" +
"sun.net.httpserver.maxReqHeaderSize) exceeded, " +
ServerConfig.getMaxReqHeaderSize() + ".");
}
}
lineBuf.append (buf, 0, pos);
return new String (lineBuf);
}
private void consume (int c) {
private void consume (int c) throws IOException {
if (pos == BUF_LEN) {
lineBuf.append (buf);
pos = 0;
@@ -139,13 +149,22 @@ class Request {
len = 1;
firstc = c;
}
long hsize = startLine.length() + 32L;
while (firstc != LF && firstc != CR && firstc >= 0) {
int keyend = -1;
int c;
boolean inKey = firstc > ' ';
s[len++] = (char) firstc;
hsize = hsize + 1;
parseloop:{
// We start parsing for a new name value pair here.
// The max header size includes an overhead of 32 bytes per
// name value pair.
// See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
long maxRemaining = maxReqHeaderSize > 0
? maxReqHeaderSize - hsize - 32
: Long.MAX_VALUE;
while ((c = is.read()) >= 0) {
switch (c) {
/*fallthrough*/
@@ -179,6 +198,11 @@ class Request {
s = ns;
}
s[len++] = (char) c;
if (maxReqHeaderSize > 0 && len > maxRemaining) {
throw new IOException("Maximum header (" +
"sun.net.httpserver.maxReqHeaderSize) exceeded, " +
ServerConfig.getMaxReqHeaderSize() + ".");
}
}
firstc = -1;
}
@@ -206,6 +230,13 @@ class Request {
"sun.net.httpserver.maxReqHeaders) exceeded, " +
ServerConfig.getMaxReqHeaders() + ".");
}
hsize = hsize + len + 32;
if (maxReqHeaderSize > 0 && hsize > maxReqHeaderSize) {
throw new IOException("Maximum header (" +
"sun.net.httpserver.maxReqHeaderSize) exceeded, " +
ServerConfig.getMaxReqHeaderSize() + ".");
}
if (k == null) { // Headers disallows null keys, use empty string
k = ""; // instead to represent invalid key
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2024, 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
@@ -48,6 +48,7 @@ class ServerConfig {
// timing out request/response if max request/response time is configured
private static final long DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS = 1000;
private static final int DEFAULT_MAX_REQ_HEADERS = 200;
private static final int DEFAULT_MAX_REQ_HEADER_SIZE = 380 * 1024;
private static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024;
private static long idleTimerScheduleMillis;
@@ -61,6 +62,9 @@ class ServerConfig {
private static int maxIdleConnections;
// The maximum number of request headers allowable
private static int maxReqHeaders;
// a maximum value for the header list size. This is the
// names size + values size + 32 bytes per field line
private static int maxReqHeadersSize;
// max time a request or response is allowed to take
private static long maxReqTime;
private static long maxRspTime;
@@ -103,6 +107,14 @@ class ServerConfig {
"sun.net.httpserver.maxReqHeaders",
DEFAULT_MAX_REQ_HEADERS);
// a value <= 0 means unlimited
maxReqHeadersSize = Integer.getInteger(
"sun.net.httpserver.maxReqHeaderSize",
DEFAULT_MAX_REQ_HEADER_SIZE);
if (maxReqHeadersSize <= 0) {
maxReqHeadersSize = 0;
}
maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime",
DEFAULT_MAX_REQ_TIME);
@@ -211,6 +223,10 @@ class ServerConfig {
return maxReqHeaders;
}
static int getMaxReqHeaderSize() {
return maxReqHeadersSize;
}
/**
* @return Returns the maximum amount of time the server will wait for the request to be read
* completely. This method can return a value of 0 or negative to imply no maximum limit has

View File

@@ -42,7 +42,7 @@ import javax.security.auth.spi.*;
import sun.security.krb5.*;
import sun.security.jgss.krb5.Krb5Util;
import sun.security.krb5.Credentials;
import sun.security.util.HexDumpEncoder;
import static sun.security.util.ResourcesMgr.getAuthResourceString;
/**
@@ -760,15 +760,11 @@ public class Krb5LoginModule implements LoginModule {
if (debug) {
System.out.println("principal is " + principal);
HexDumpEncoder hd = new HexDumpEncoder();
if (ktab != null) {
System.out.println("Will use keytab");
} else if (storeKey) {
for (int i = 0; i < encKeys.length; i++) {
System.out.println("EncryptionKey: keyType=" +
encKeys[i].getEType() +
" keyBytes (hex dump)=" +
hd.encodeBuffer(encKeys[i].getBytes()));
System.out.println(encKeys[i].toString());
}
}
}
@@ -869,7 +865,7 @@ public class Krb5LoginModule implements LoginModule {
}
if (debug) {
System.out.println
("password is " + new String(password));
("Get password from shared state");
}
return;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, 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
@@ -24,10 +24,13 @@
#include "precompiled.hpp"
#include "gc/shared/memset_with_concurrent_readers.hpp"
#include "utilities/globalDefinitions.hpp"
#include "unittest.hpp"
#include "utilities/vmassert_uninstall.hpp"
#include <string.h>
#include <sstream>
#include "utilities/vmassert_reinstall.hpp"
#include "unittest.hpp"
static unsigned line_byte(const char* line, size_t i) {
return unsigned(line[i]) & 0xFF;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@@ -42,11 +42,13 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
#include "unittest.hpp"
#include "utilities/vmassert_uninstall.hpp"
#include <vector>
#include <list>
#include <map>
#include "utilities/vmassert_reinstall.hpp"
#include "unittest.hpp"
namespace {

View File

@@ -28,19 +28,10 @@
#include <stdio.h>
#define GTEST_DONT_DEFINE_TEST 1
#include "gtest/gtest.h"
// gtest/gtest.h includes assert.h which will define the assert macro, but hotspot has its
// own standards incompatible assert macro that takes two parameters.
// The workaround is to undef assert and then re-define it. The re-definition
// must unfortunately be copied since debug.hpp might already have been
// included and a second include wouldn't work due to the header guards in debug.hpp.
#ifdef assert
#undef assert
#ifdef vmassert
#define assert(p, ...) vmassert(p, __VA_ARGS__)
#endif
#endif
#include "utilities/vmassert_uninstall.hpp"
#include "gtest/gtest.h"
#include "utilities/vmassert_reinstall.hpp"
#define CONCAT(a, b) a ## b

View File

@@ -24,14 +24,41 @@
package gc.stress;
/*
* @test TestStressG1Humongous
* @test
* @key gc stress
* @summary Stress G1 by humongous allocations in situation near OOM
* @requires vm.gc.G1
* @requires !vm.flightRecorder
* @library /test/lib
* @modules java.base/jdk.internal.misc
* @run driver/timeout=1300 gc.stress.TestStressG1Humongous
* @run driver/timeout=180 gc.stress.TestStressG1Humongous 4 3 1.1 120
*/
/*
* @test
* @requires vm.gc.G1
* @requires !vm.flightRecorder
* @library /test/lib
* @modules java.base/jdk.internal.misc
* @run driver/timeout=180 gc.stress.TestStressG1Humongous 16 5 2.1 120
*/
/*
* @test
* @requires vm.gc.G1
* @requires !vm.flightRecorder
* @library /test/lib
* @modules java.base/jdk.internal.misc
* @run driver/timeout=180 gc.stress.TestStressG1Humongous 32 4 0.6 120
*/
/*
* @test
* @requires vm.gc.G1
* @requires !vm.flightRecorder
* @library /test/lib
* @modules java.base/jdk.internal.misc
* @run driver/timeout=900 gc.stress.TestStressG1Humongous 1 7 0.6 600
*/
import java.util.ArrayList;
@@ -48,17 +75,19 @@ import jdk.test.lib.process.OutputAnalyzer;
public class TestStressG1Humongous{
public static void main(String[] args) throws Exception {
if (args.length != 4) {
throw new IllegalArgumentException("Test expects 4 arguments");
}
// Limit heap size on 32-bit platforms
int heapSize = Platform.is32bit() ? 512 : 1024;
// Heap size, region size, threads, humongous size, timeout
run(heapSize, 4, 3, 1.1, 120);
run(heapSize, 16, 5, 2.1, 120);
run(heapSize, 32, 4, 0.6, 120);
run(heapSize, 1, 7, 0.6, 600);
}
private static void run(int heapSize, int regionSize, int threads, double humongousSize, int timeout)
throws Exception {
// Region size, threads, humongous size, and timeout passed as @run arguments
int regionSize = Integer.parseInt(args[0]);
int threads = Integer.parseInt(args[1]);
double humongousSize = Double.parseDouble(args[2]);
int timeout = Integer.parseInt(args[3]);
ArrayList<String> options = new ArrayList<>();
Collections.addAll(options, Utils.getTestJavaOpts());
Collections.addAll(options,

View File

@@ -710,7 +710,6 @@ javax/swing/JComboBox/8182031/ComboPopupTest.java 8196465 linux-all,macosx-all
javax/swing/JFileChooser/6738668/bug6738668.java 8194946 generic-all
javax/swing/JFileChooser/8062561/bug8062561.java 8196466 linux-all,macosx-all
javax/swing/JInternalFrame/Test6325652.java 8196467 macosx-all
javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java 8225045 linux-all
javax/swing/JLabel/6596966/bug6596966.java 8040914 macosx-all
javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all
javax/swing/JSpinner/8223788/JSpinnerButtonFocusTest.java 8238085 macosx-all
@@ -838,8 +837,6 @@ sun/tools/jhsdb/HeapDumpTest.java 8193639 solaris-
# jdk_other
com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java 8169942 linux-i586,macosx-all,windows-x64
com/sun/jndi/dns/ConfigTests/PortUnreachable.java 7164518 macosx-all
javax/rmi/ssl/SSLSocketParametersTest.sh 8162906 generic-all

View File

@@ -24,18 +24,23 @@
/**
* @test
* @bug 6449574
* @library /test/lib
* @summary Invalid ldap filter is accepted and processed
*/
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Properties;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Hashtable;
import java.net.Socket;
import java.net.ServerSocket;
import jdk.test.lib.net.URIBuilder;
public class BalancedParentheses {
// Should we run the client or server in a separate thread?
//
@@ -54,7 +59,13 @@ public class BalancedParentheses {
// If the server prematurely exits, serverReady will be set to true
// to avoid infinite hangs.
void doServerSide() throws Exception {
ServerSocket serverSock = new ServerSocket(serverPort);
// Create unbound server socket
ServerSocket serverSock = new ServerSocket();
// And bind it to the loopback address
SocketAddress sockAddr = new InetSocketAddress(
InetAddress.getLoopbackAddress(), 0);
serverSock.bind(sockAddr);
// signal client, it's ready to accecpt connection
serverPort = serverSock.getLocalPort();
@@ -106,7 +117,13 @@ public class BalancedParentheses {
Hashtable<Object, Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:" + serverPort);
// Construct the provider URL
String providerURL = URIBuilder.newBuilder()
.scheme("ldap")
.loopback()
.port(serverPort)
.build().toString();
env.put(Context.PROVIDER_URL, providerURL);
env.put("com.sun.jndi.ldap.read.timeout", "1000");
// env.put(Context.SECURITY_AUTHENTICATION, "simple");

View File

@@ -21,34 +21,35 @@
* questions.
*/
/**
/*
* @test
* @run main/othervm DeadSSLLdapTimeoutTest
* @bug 8141370
* @key intermittent
* @library /test/lib
* @build DeadSSLSocketFactory
* @run main/othervm DeadSSLLdapTimeoutTest
*/
import java.net.Socket;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.naming.directory.InitialDirContext;
import javax.net.ssl.SSLHandshakeException;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import jdk.test.lib.net.URIBuilder;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -57,26 +58,26 @@ class DeadServerTimeoutSSLTest implements Callable<Boolean> {
Hashtable<Object, Object> env;
DeadSSLServer server;
boolean passed = false;
private int HANGING_TEST_TIMEOUT = 20_000;
public DeadServerTimeoutSSLTest(Hashtable<Object, Object> env) throws IOException {
this.server = new DeadSSLServer();
SocketAddress sockAddr = new InetSocketAddress(
InetAddress.getLoopbackAddress(), 0);
this.server = new DeadSSLServer(sockAddr);
this.env = env;
}
public void performOp(InitialContext ctx) throws NamingException {}
public void handleNamingException(NamingException e, long start, long end) {
public void handleNamingException(NamingException e) {
if (e.getCause() instanceof SocketTimeoutException
|| e.getCause().getCause() instanceof SocketTimeoutException) {
// SSL connect will timeout via readReply using
// SocketTimeoutException
e.printStackTrace();
System.out.println("PASS: Observed expected SocketTimeoutException");
pass();
} else if (e.getCause() instanceof SSLHandshakeException
&& e.getCause().getCause() instanceof EOFException) {
// test seems to be failing intermittently on some
// platforms.
System.out.println("PASS: Observed expected SSLHandshakeException/EOFException");
pass();
} else {
fail(e);
@@ -92,6 +93,7 @@ class DeadServerTimeoutSSLTest implements Callable<Boolean> {
}
public void fail(Exception e) {
System.err.println("FAIL: Unexpected exception was observed:" + e.getMessage());
throw new RuntimeException("Test failed", e);
}
@@ -106,34 +108,36 @@ class DeadServerTimeoutSSLTest implements Callable<Boolean> {
public Boolean call() {
InitialContext ctx = null;
ScheduledFuture<?> killer = null;
long start = System.nanoTime();
try {
while(!server.accepting())
Thread.sleep(200); // allow the server to start up
server.serverStarted.await(); // Wait for the server to start-up
Thread.sleep(200); // to be sure
env.put(Context.PROVIDER_URL, "ldap://localhost:" +
server.getLocalPort());
env.put(Context.PROVIDER_URL,
URIBuilder.newBuilder()
.scheme("ldap")
.loopback()
.port(server.getLocalPort())
.buildUnchecked().toString()
);
long start = System.nanoTime();
try {
ctx = new InitialDirContext(env);
performOp(ctx);
fail();
} catch (NamingException e) {
long end = System.nanoTime();
System.out.println(this.getClass().toString() + " - elapsed: "
+ NANOSECONDS.toMillis(end - start));
handleNamingException(e, start, end);
handleNamingException(e);
} finally {
if (killer != null && !killer.isDone())
killer.cancel(true);
// Stop the server side thread
server.testDone.countDown();
shutItDown(ctx);
server.close();
}
return passed;
} catch (IOException|InterruptedException e) {
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}
@@ -141,20 +145,69 @@ class DeadServerTimeoutSSLTest implements Callable<Boolean> {
class DeadSSLServer extends Thread {
ServerSocket serverSock;
boolean accepting = false;
// Latch to be used by client to wait for server to start
CountDownLatch serverStarted = new CountDownLatch(1);
public DeadSSLServer() throws IOException {
this.serverSock = new ServerSocket(0);
// Latch to be used by server thread to wait for client to finish testing
CountDownLatch testDone = new CountDownLatch(1);
public DeadSSLServer(SocketAddress socketAddress) throws IOException {
// create unbound server socket
var srvSock = new ServerSocket();
// bind it to the address provided
srvSock.bind(socketAddress);
this.serverSock = srvSock;
start();
}
public void run() {
while(true) {
try {
accepting = true;
Socket socket = serverSock.accept();
// Signal client to proceed with the test
serverStarted.countDown();
while (true) {
try (var acceptedSocket = serverSock.accept()) {
System.err.println("Accepted connection:" + acceptedSocket);
int iteration = 0;
// Wait for socket to get opened by DeadSSLSocketFactory and connected to the test server
while (iteration++ < 20) {
if (DeadSSLSocketFactory.firstCreatedSocket.get() != null &&
DeadSSLSocketFactory.firstCreatedSocket.get().isConnected()) {
break;
}
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ie) {
}
}
Socket clientSideSocket = DeadSSLSocketFactory.firstCreatedSocket.get();
System.err.printf("Got SSLSocketFactory connection after %d iterations: %s%n",
iteration, clientSideSocket);
if (clientSideSocket == null || !clientSideSocket.isConnected()) {
// If after 1000 ms client side connection is not opened - probably other local process
// tried to connect to the test server socket. Close current connection and retry accept.
continue;
} else {
// Check if accepted socket is connected to the LDAP client
if (acceptedSocket.getLocalPort() == clientSideSocket.getPort() &&
acceptedSocket.getPort() == clientSideSocket.getLocalPort() &&
acceptedSocket.getInetAddress().equals(clientSideSocket.getLocalAddress())) {
System.err.println("Accepted connection is originated from LDAP client:" + acceptedSocket);
try {
// Give LDAP client time to fully establish the connection.
// When client is done - the accepted socket will be closed
testDone.await();
} catch (InterruptedException e) {
}
break;
} else {
// If accepted socket is not from the LDAP client - the accepted connection will be closed and new
// one will be accepted
System.err.println("SSLSocketFactory connection has been established, but originated not from" +
" the test's LDAP client:" + acceptedSocket);
}
}
} catch (Exception e) {
break;
System.err.println("Server socket. Failure to accept connection:" + e.getMessage());
}
}
}
@@ -163,28 +216,26 @@ class DeadSSLServer extends Thread {
return serverSock.getLocalPort();
}
public boolean accepting() {
return accepting;
}
public void close() throws IOException {
serverSock.close();
}
}
public class DeadSSLLdapTimeoutTest {
// com.sun.jndi.ldap.connect.timeout value to set
static final String CONNECT_TIMEOUT_MS = "10";
// com.sun.jndi.ldap.read.timeout value to set
static final String READ_TIMEOUT_MS = "3000";
static Hashtable<Object, Object> createEnv() {
Hashtable<Object, Object> env = new Hashtable<>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
"com.sun.jndi.ldap.LdapCtxFactory");
return env;
}
public static void main(String[] args) throws Exception {
InitialContext ctx = null;
//
// Running this test serially as it seems to tickle a problem
// on older kernels
@@ -193,19 +244,24 @@ public class DeadSSLLdapTimeoutTest {
// and ssl enabled
// this should exit with a SocketTimeoutException as the root cause
// it should also use the connect timeout instead of the read timeout
System.out.println("Running connect timeout test with 10ms connect timeout, 3000ms read timeout & SSL");
Hashtable<Object, Object> sslenv = createEnv();
sslenv.put("com.sun.jndi.ldap.connect.timeout", "10");
sslenv.put("com.sun.jndi.ldap.read.timeout", "3000");
sslenv.put(Context.SECURITY_PROTOCOL, "ssl");
boolean testFailed =
(new DeadServerTimeoutSSLTest(sslenv).call()) ? false : true;
System.out.printf("Running connect timeout test with %sms connect timeout," +
" %sms read timeout & SSL%n",
CONNECT_TIMEOUT_MS, READ_TIMEOUT_MS);
Hashtable<Object, Object> sslenv = createEnv();
// Setup connect timeout environment property
sslenv.put("com.sun.jndi.ldap.connect.timeout", CONNECT_TIMEOUT_MS);
// Setup read timeout environment property
sslenv.put("com.sun.jndi.ldap.read.timeout", READ_TIMEOUT_MS);
// Setup DeadSSLSocketFactory to track the client's first LDAP connection
sslenv.put("java.naming.ldap.factory.socket", "DeadSSLSocketFactory");
// Use SSL protocol
sslenv.put(Context.SECURITY_PROTOCOL, "ssl");
boolean testFailed = !new DeadServerTimeoutSSLTest(sslenv).call();
if (testFailed) {
throw new AssertionError("some tests failed");
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2020, 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 javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/*
* A custom socket factory used to override the default socket factory and track the LDAP client connection.
* Factory can create only one SSLSocket. See the DeadServerTimeoutSSLTest test.
*/
public class DeadSSLSocketFactory extends SocketFactory {
// Client socket that is used by LDAP connection
public static AtomicReference<SSLSocket> firstCreatedSocket = new AtomicReference<>();
// Boolean to track if connection socket has been opened
public static AtomicBoolean isConnectionOpened = new AtomicBoolean(false);
// Default SSLSocketFactory that will be used for SSL socket creation
final SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
// Create unconnected socket
public Socket createSocket() throws IOException {
if (!isConnectionOpened.getAndSet(true)) {
System.err.println("DeadSSLSocketFactory: Creating unconnected socket");
firstCreatedSocket.set((SSLSocket) factory.createSocket());
return firstCreatedSocket.get();
} else {
throw new RuntimeException("DeadSSLSocketFactory only allows creation of one SSL socket");
}
}
public DeadSSLSocketFactory() {
System.err.println("DeadSSLSocketFactory: Constructor call");
}
public static SocketFactory getDefault() {
System.err.println("DeadSSLSocketFactory: acquiring DeadSSLSocketFactory as default socket factory");
return new DeadSSLSocketFactory();
}
@Override
public Socket createSocket(String host, int port) throws IOException {
// Not used by DeadSSLLdapTimeoutTest
return factory.createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException {
// Not used by DeadSSLLdapTimeoutTest
return factory.createSocket(host, port, localHost, localPort);
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
// Not used by DeadSSLLdapTimeoutTest
return factory.createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
// Not used by DeadSSLLdapTimeoutTest
return factory.createSocket(address, port, localAddress, localPort);
}
}

View File

@@ -27,7 +27,7 @@
* @summary Verify capability to add a new entry to the directory using the
* ADD operation.
* @modules java.naming/com.sun.jndi.ldap
* @library ../../lib/ /javax/naming/module/src/test/test/
* @library /test/lib ../../lib/ /javax/naming/module/src/test/test/
* @build LDAPServer LDAPTestUtils
* @run main/othervm AddNewEntry
*/
@@ -41,19 +41,36 @@ import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.util.Hashtable;
import jdk.test.lib.net.URIBuilder;
public class AddNewEntry {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(0);
// Create unbound server socket
ServerSocket serverSocket = new ServerSocket();
// Bind it to the loopback address
SocketAddress sockAddr = new InetSocketAddress(
InetAddress.getLoopbackAddress(), 0);
serverSocket.bind(sockAddr);
// Construct the provider URL for LDAPTestUtils
String providerURL = URIBuilder.newBuilder()
.scheme("ldap")
.loopback()
.port(serverSocket.getLocalPort())
.buildUnchecked().toString();
Hashtable<Object, Object> env;
// initialize test
env = LDAPTestUtils
.initEnv(serverSocket, AddNewEntry.class.getName(), args, true);
env = LDAPTestUtils.initEnv(serverSocket, providerURL,
AddNewEntry.class.getName(), args, true);
/* Build attribute set */
String[] ids = { "objectClass", "sn", "cn", "telephoneNumber", "mail",

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@@ -50,12 +50,17 @@ public class LDAPTestUtils {
* Process command line arguments and return properties in a Hashtable.
*/
public static Hashtable<Object, Object> initEnv(String testname,
String[] args) {
String[] args) {
return initEnv(null, testname, args, false);
}
public static Hashtable<Object, Object> initEnv(ServerSocket socket,
String testname, String[] args, boolean authInfo) {
String testname, String[] args, boolean authInfo) {
return initEnv(socket, null, testname, args, authInfo);
}
public static Hashtable<Object, Object> initEnv(ServerSocket socket, String providerUrl,
String testname, String[] args, boolean authInfo) {
Hashtable<Object, Object> env = new Hashtable<>();
String root = "o=IMC,c=US";
@@ -103,8 +108,9 @@ public class LDAPTestUtils {
if (socket != null) {
env.put(TEST_LDAP_SERVER_THREAD,
startLDAPServer(socket, getCaptureFile(testname)));
env.put("java.naming.provider.url",
"ldap://localhost:" + socket.getLocalPort());
String url = providerUrl != null ? providerUrl :
"ldap://localhost:" + socket.getLocalPort();
env.put("java.naming.provider.url", url);
} else {
// for tests which run against remote server or no server
// required

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2022, 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.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.util.Hashtable;
import javax.naming.CommunicationException;
import javax.naming.NamingException;
import javax.naming.ServiceUnavailableException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import jdk.test.lib.net.URIBuilder;
/**
* @test
* @bug 8290367
* @summary Check if com.sun.jndi.ldap.object.trustSerialData covers the creation
* of RMI remote objects from the 'javaRemoteLocation' LDAP attribute.
* @modules java.naming/com.sun.jndi.ldap
* @library /test/lib ../lib /javax/naming/module/src/test/test/
* @build LDAPServer LDAPTestUtils
*
* @run main/othervm RemoteLocationAttributeTest
* @run main/othervm -Dcom.sun.jndi.ldap.object.trustSerialData
* RemoteLocationAttributeTest
* @run main/othervm -Dcom.sun.jndi.ldap.object.trustSerialData=false
* RemoteLocationAttributeTest
* @run main/othervm -Dcom.sun.jndi.ldap.object.trustSerialData=true
* RemoteLocationAttributeTest
* @run main/othervm -Dcom.sun.jndi.ldap.object.trustSerialData=TrUe
* RemoteLocationAttributeTest
*/
public class RemoteLocationAttributeTest {
public static void main(String[] args) throws Exception {
// Create unbound server socket
ServerSocket serverSocket = new ServerSocket();
// Bind it to the loopback address
SocketAddress sockAddr = new InetSocketAddress(
InetAddress.getLoopbackAddress(), 0);
serverSocket.bind(sockAddr);
// Construct the provider URL for LDAPTestUtils
String providerURL = URIBuilder.newBuilder()
.scheme("ldap")
.loopback()
.port(serverSocket.getLocalPort())
.buildUnchecked().toString();
Hashtable<Object, Object> env;
// Initialize test environment variables
env = LDAPTestUtils.initEnv(serverSocket, providerURL,
RemoteLocationAttributeTest.class.getName(), args, false);
DirContext ctx = null;
try (serverSocket) {
System.err.println(env);
// connect to server
ctx = new InitialDirContext(env);
Object lookupResult = ctx.lookup("Test");
System.err.println("Lookup result:" + lookupResult);
// Test doesn't provide RMI registry running at 127.0.0.1:1097, but if
// there is one running on test host successful result is valid for
// cases when reconstruction allowed.
if (!RECONSTRUCTION_ALLOWED) {
throw new AssertionError("Unexpected successful lookup");
}
} catch (ServiceUnavailableException | CommunicationException connectionException) {
// The remote location was properly reconstructed but connection to
// RMI endpoint failed:
// ServiceUnavailableException - no open socket on 127.0.0.1:1097
// CommunicationException - 127.0.0.1:1097 is open, but it is not RMI registry
System.err.println("Got one of connection exceptions:" + connectionException);
if (!RECONSTRUCTION_ALLOWED) {
throw new AssertionError("Reconstruction not blocked, as expected");
}
} catch (NamingException ne) {
String message = ne.getMessage();
System.err.printf("Got NamingException with message: '%s'%n", message);
if (RECONSTRUCTION_ALLOWED && EXPECTED_NAMING_EXCEPTION_MESSAGE.equals(message)) {
throw new AssertionError("Reconstruction unexpectedly blocked");
}
if (!RECONSTRUCTION_ALLOWED && !EXPECTED_NAMING_EXCEPTION_MESSAGE.equals(message)) {
throw new AssertionError("Reconstruction not blocked");
}
} finally {
LDAPTestUtils.cleanup(ctx);
}
}
// Reconstruction of RMI remote objects is allowed if 'com.sun.jndi.ldap.object.trustSerialData'
// is set to "true". If the system property is not specified it implies default "false" value
private static final boolean RECONSTRUCTION_ALLOWED =
Boolean.getBoolean("com.sun.jndi.ldap.object.trustSerialData");
// NamingException message when reconstruction is not allowed
private static final String EXPECTED_NAMING_EXCEPTION_MESSAGE = "Object deserialization is not allowed";
}

View File

@@ -0,0 +1,61 @@
#
# Copyright (c) 2022, 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.
#
################################################################################
# Capture file for RemoteLocationAttributeTest.java
#
# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
# running the RemoteLocationAttributeTest application program against
# a real LDAP server and setting the JNDI/LDAP environment property:
# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
#
################################################################################
# LDAP BindRequest
0000: 30 0C 02 01 01 60 07 02 01 03 04 00 80 00 0....`........
# LDAP BindResponse
0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........
# LDAP SearchRequest
0000: 30 46 02 01 02 63 24 04 04 54 65 73 74 0A 01 00 0F...c$..Test...
0010: 0A 01 03 02 01 00 02 01 00 01 01 00 87 0B 6F 62 ..............ob
0020: 6A 65 63 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 jectClass0...0..
0030: 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 .2.16.840.1.1137
0040: 33 30 2E 33 2E 34 2E 32 30.3.4.2
# LDAP SearchResultEntry
0000: 30 5E 02 01 02 64 59 04 04 54 65 73 74 30 51 30 0^...dY..Test0Q0
0010: 16 04 0D 6A 61 76 61 43 6C 61 73 73 4E 61 6D 65 ...javaClassName
0020: 31 05 04 03 66 6F 6F 30 37 04 12 6A 61 76 61 52 1...foo07..javaR
0030: 65 6D 6F 74 65 4C 6F 63 61 74 69 6F 6E 31 21 04 emoteLocation1!.
0040: 1F 72 6D 69 3A 2F 2F 31 32 37 2E 30 2E 30 2E 31 .rmi://127.0.0.1
0050: 3A 31 30 39 37 2F 54 65 73 74 52 65 6D 6F 74 65 :1097/TestRemote
# LDAP SearchResultDone
0000: 30 0C 02 01 02 65 07 0A 01 00 04 00 04 00 0....e........
# LDAP UnbindRequest
0000: 30 22 02 01 03 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1
0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3
0020: 2E 34 2E 32 .4.2

View File

@@ -1,43 +0,0 @@
<html>
<!--
Copyright (c) 2013, 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 6243382 8006070
@summary Dragging of mouse outside of a List and Choice area don't work properly on XAWT
@author Dmitry.Cherepanov@SUN.COM area=awt.list
@run applet/manual=yesno MouseDraggedOutCauseScrollingTest.html
-->
<head>
<title> ManualYesNoTest </title>
</head>
<body>
<h1>ManualYesNoTest<br>Bug ID: </h1>
<p> See the dialog box (usually in upper left corner) for instructions</p>
<APPLET CODE="MouseDraggedOutCauseScrollingTest.class" WIDTH=200 HEIGHT=200></APPLET>
</body>
</html>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2024, 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
@@ -22,29 +22,29 @@
*/
/*
test
@test
@bug 6243382 8006070
@summary Dragging of mouse outside of a List and Choice area don't work properly on XAWT
@author Dmitry.Cherepanov@SUN.COM area=awt.list
@run applet/manual=yesno MouseDraggedOutCauseScrollingTest.html
@requires (os.family == "linux")
@library /java/awt/regtesthelpers
@run main/manual MouseDraggedOutCauseScrollingTest
*/
import java.applet.Applet;
import java.awt.*;
import java.awt.Choice;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.List;
import java.awt.Toolkit;
public class MouseDraggedOutCauseScrollingTest extends Applet
{
Choice choice;
List singleList;
List multipleList;
public class MouseDraggedOutCauseScrollingTest {
public void init()
{
this.setLayout (new GridLayout (1, 3));
static Frame createUI() {
Frame frame = new Frame("MouseDraggedOutCausesScrollingTest");
frame.setLayout(new GridLayout(1, 3));
choice = new Choice();
singleList = new List(3, false);
multipleList = new List(3, true);
Choice choice = new Choice();
List singleList = new List(3, false);
List multipleList = new List(3, true);
choice.add("Choice");
for (int i = 1; i < 100; i++){
@@ -59,188 +59,66 @@ public class MouseDraggedOutCauseScrollingTest extends Applet
for (int i = 1; i < 100; i++)
multipleList.add(""+i);
this.add(choice);
this.add(singleList);
this.add(multipleList);
frame.add(choice);
frame.add(singleList);
frame.add(multipleList);
frame.setSize(400, 100);
return frame;
}
public static void main(String[] args) throws Exception {
String toolkitName = Toolkit.getDefaultToolkit().getClass().getName();
if (!toolkitName.equals("sun.awt.X11.XToolkit")) {
String[] instructions =
{
"This test is not applicable to the current platform. Press PASS"
};
Sysout.createDialogWithInstructions( instructions );
} else {
String[] instructions =
{
"0) Please note, that this is only Motif/XAWT test. At first, make the applet active",
"1.1) Click on the choice",
"1.2) Press the left button of the mouse and keep on any item of the choice, for example 5",
"1.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same",
"1.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling UP of the list and selected item changes on the upper. If not, the test failed",
"1.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling DOWN of the list and selected item changes on the lower. If not, the test failed",
"-----------------------------------",
"2.1) Click on the single list",
"2.2) Press the left button of the mouse and keep on any item of the list, for example 5",
"2.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same",
"2.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling UP of the list and selected item changes on the upper. If not, the test failed",
"2.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling DOWN of the list and selected item changes on the lower. If not, the test failed",
"-----------------------------------",
"3.1) Click on the multiple list",
"3.2) Press the left button of the mouse and keep on any item of the list, for example 5",
"3.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same",
"3.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling of the list NO OCCURED and selected item NO CHANGES on the upper. If not, the test failed",
"3.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling of the list NO OCCURED and selected item NO CHANGES on the lower. If not, the test failed",
"4) Test passed."
};
Sysout.createDialogWithInstructions( instructions );
System.out.println(INAPPLICABLE);
return;
}
}//End init()
public void start ()
{
setSize (400,100);
setVisible(true);
validate();
}// start()
}// class ManualYesNoTest
/****************************************************
Standard Test Machinery
DO NOT modify anything below -- it's a standard
chunk of code whose purpose is to make user
interaction uniform, and thereby make it simpler
to read and understand someone else's test.
****************************************************/
/**
This is part of the standard test machinery.
It creates a dialog (with the instructions), and is the interface
for sending text messages to the user.
To print the instructions, send an array of strings to Sysout.createDialog
WithInstructions method. Put one line of instructions per array entry.
To display a message for the tester to see, simply call Sysout.println
with the string to be displayed.
This mimics System.out.println but works within the test harness as well
as standalone.
*/
class Sysout
{
private static TestDialog dialog;
public static void createDialogWithInstructions( String[] instructions )
{
dialog = new TestDialog( new Frame(), "Instructions" );
dialog.printInstructions( instructions );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
PassFailJFrame
.builder()
.instructions(INSTRUCTIONS)
.rows(40)
.columns(70)
.testUI(MouseDraggedOutCauseScrollingTest::createUI)
.build()
.awaitAndCheck();
}
public static void createDialog( )
{
dialog = new TestDialog( new Frame(), "Instructions" );
String[] defInstr = { "Instructions will appear here. ", "" } ;
dialog.printInstructions( defInstr );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
public static void printInstructions( String[] instructions )
{
dialog.printInstructions( instructions );
}
public static void println( String messageIn )
{
dialog.displayMessage( messageIn );
}
}// Sysout class
/**
This is part of the standard test machinery. It provides a place for the
test instructions to be displayed, and a place for interactive messages
to the user to be displayed.
To have the test instructions displayed, see Sysout.
To have a message to the user be displayed, see Sysout.
Do not call anything in this dialog directly.
*/
class TestDialog extends Dialog
{
TextArea instructionsText;
TextArea messageText;
int maxStringLength = 80;
//DO NOT call this directly, go through Sysout
public TestDialog( Frame frame, String name )
{
super( frame, name );
int scrollBoth = TextArea.SCROLLBARS_BOTH;
instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
add( "North", instructionsText );
messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
add("Center", messageText);
pack();
setVisible(true);
}// TestDialog()
//DO NOT call this directly, go through Sysout
public void printInstructions( String[] instructions )
{
//Clear out any current instructions
instructionsText.setText( "" );
//Go down array of instruction strings
String printStr, remainingStr;
for( int i=0; i < instructions.length; i++ )
{
//chop up each into pieces maxSringLength long
remainingStr = instructions[ i ];
while( remainingStr.length() > 0 )
{
//if longer than max then chop off first max chars to print
if( remainingStr.length() >= maxStringLength )
{
//Try to chop on a word boundary
int posOfSpace = remainingStr.
lastIndexOf( ' ', maxStringLength - 1 );
if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
printStr = remainingStr.substring( 0, posOfSpace + 1 );
remainingStr = remainingStr.substring( posOfSpace + 1 );
}
//else just print
else
{
printStr = remainingStr;
remainingStr = "";
}
instructionsText.append( printStr + "\n" );
}// while
}// for
}//printInstructions()
//DO NOT call this directly, go through Sysout
public void displayMessage( String messageIn )
{
messageText.append( messageIn + "\n" );
System.out.println(messageIn);
}
}// TestDialog class
static final String INAPPLICABLE = "The test is not applicable to the current platform. Test PASSES.";
static final String INSTRUCTIONS = "0) Please note, that this is an XAWT/Linux only test. First, make the test window is active.\n" +
"-----------------------------------\n" +
"1.1) Click on the Choice.\n" +
"1.2) Press and hold down the left button of the mouse to select (eg) item 5 in the choice.\n" +
"1.3) Drag the mouse vertically out of the area of the open list,\n" +
" keeping the X coordinate of the mouse position about the same.\n" +
"1.4) Check that when the Y coordinate of the mouse position is higher than the upper bound of the list\n" +
" then the list continues to scrolls UP and the selected item changes at the top until you reach the topmost item.\n" +
" If not, the test failed. Press FAIL.\n" +
"1.5) Check that when the Y coordinate of the mouse position is lower than the lower bound of the list\n" +
" then the list continues to scroll DOWN and the selected item changes at the bottom until you reach the bottommost item.\n" +
" If not, the test failed. Press FAIL.\n" +
"-----------------------------------\n" +
"2.1) Click on the Single List.\n" +
"2.2) Press and hold down the left button of the mouse to select (eg) item 5 in the list.\n" +
"2.3) Drag the mouse vertically out of the area of the open list,\n" +
" keeping the X coordinate of the mouse position about the same.\n" +
"2.4) Check that when the Y coordinate of the mouse position is higher than the upper bound of the list\n" +
" then the list continues to scrolls UP and the selected item changes at the top until you reach the topmost item.\n" +
" If not, the test failed. Press FAIL.\n" +
"2.5) Check that when the Y coordinate of the mouse position is lower than the lower bound of the list\n" +
" then the list continues to scroll DOWN and the selected item changes at the bottom until you reach the bottommost item.\n" +
" If not, the test failed. Press FAIL.\n" +
"-----------------------------------\n" +
"3.1) Click on the Multiple List.\n" +
"3.2) Press and hold down the left button of the mouse to select (eg) item 5 in the list.\n" +
"3.3) Drag the mouse vertically out of the area of the open list,\n" +
" keeping the X coordinate of the mouse position about the same.\n" +
"3.4) Check that when the Y coordinate of the mouse is higher than the upper bound of the list\n" +
" that scrolling of the list DOES NOT OCCUR and the selected item IS UNCHANGED at the top.\n" +
" If not, the test failed. Press FAIL.\n" +
"3.5) Check that when the Y coordinate of the mouse is below the lower bound of the list\n" +
" that scrolling of the list DOES NOT OCCUR and the selected item IS UNCHANGED at the bottom.\n" +
" If not, the test failed. Press FAIL.\n" +
"-----------------------------------\n" +
"4) The test has now passed. Press PASS.";
}

View File

@@ -1,44 +0,0 @@
<!--
Copyright (c) 2007, 2014, 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.
-->
<html>
<head>
<title> PrintDialogsTest </title>
</head>
<body>
<applet code="PrintDialogsTest.class" width=250 height=350></applet>
Please select dialog modality type and parent; also select
the print auxiliary dialog to be displayed (Page Setup or Print dialog).
Then click "Start test" button.
When the windows will appear check if modal blocking for Dialog works as expected.
Then push "Open" button on the Dialog to show the auxiliary dialog and check
if it blocks the rest of the application. Then close it and check correctness
of modal blocking behavior for the Dialog again. To close all the test
windows please push "Finish" button.
To finish the overall test push "Pass" or "Fail" button depending on result.
</body>
</html>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2024, 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
@@ -25,21 +25,75 @@
/*
* @test
* @bug 8055836 8057694 8055752
* @summary Check if Print and Page Setup dialogs lock other windows;
* @summary Check if Print and Page Setup dialogs block other windows;
* check also correctness of modal behavior for other dialogs.
*
* @run applet/manual=yesno PrintDialogsTest.html
* @library /java/awt/regtesthelpers
* @run main/manual PrintDialogsTest
*/
import java.applet.Applet;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PrintDialogsTest extends Applet implements ActionListener {
public class PrintDialogsTest extends Panel implements ActionListener {
static final String INSTRUCTIONS =
"This test is free format, which means there is no enforced or guided sequence." + "\n" +
"Please select each of " + "\n" +
"(a) The dialog parent type." + "\n" +
"(b) The dialog modality type" + "\n" +
"(c) The print dialog type (Print dialog or Page Setup dialog)" + "\n" +
"Once the choices have been made click the \"Start test\" button." + "\n" +
"Three windows will appear" + "\n" +
"(1) A Frame or a Dialog - in the case you selected \"Dialog\" as the parent type" + "\n" +
"(2) a Window (ie an undecorated top-level)" + "\n" +
"(3) A dialog with two buttons \"Open\" and \"Finish\"" + "\n" +
"Now check as follows whether modal blocking works as expected." + "\n" +
"Windows (1) and (2) contain a button which you should be able to press" + "\n" +
"ONLY if you selected \"Non-modal\", or \"Modeless\" for modality type." + "\n" +
"In other cases window (3) will block input to (1) and (2)" + "\n" +
"Then push the \"Open\" button on the Dialog to show the printing dialog and check" + "\n" +
"if it blocks the rest of the application - ie all of windows (1), (2) and (3)" + "\n" +
"should ALWAYS be blocked when the print dialog is showing." + "\n" +
"Now cancel the printing dialog and check the correctness of modal blocking" + "\n" +
"behavior for the Dialog again." + "\n" +
"To close all the 3 test windows please push the \"Finish\" button." + "\n" +
"Repeat all the above for different combinations, which should include" + "\n" +
"using all of the Dialog parent choices and all of the Dialog Modality types." + "\n" +
"If any behave incorrectly, note the combination of choices and press Fail." + "\n" +
"If all behave correctly, press Pass.";
public static void main(String[] args) throws Exception {
PassFailJFrame.builder()
.instructions(INSTRUCTIONS)
.rows(35)
.columns(60)
.testUI(PrintDialogsTest::createUI)
.testTimeOut(10)
.build()
.awaitAndCheck();
}
private Button btnTest;
private Checkbox cbPage, cbPrint,
@@ -48,6 +102,14 @@ public class PrintDialogsTest extends Applet implements ActionListener {
private CheckboxGroup groupDialog, groupParent, groupModType;
private static Frame createUI() {
Frame frame = new Frame("Dialog Modality Testing");
PrintDialogsTest test = new PrintDialogsTest();
test.createGUI();
frame.add(test);
frame.pack();
return frame;
}
public void actionPerformed(ActionEvent e) {
@@ -99,13 +161,13 @@ public class PrintDialogsTest extends Applet implements ActionListener {
setLayout(new BorderLayout());
setSize(350, 200);
Panel panel = new Panel();
panel.setLayout(new GridLayout(18, 1));
panel.setLayout(new GridLayout(21, 1));
btnTest = new Button("Start test");
btnTest.addActionListener(this);
panel.add(btnTest);
panel.add(new Label(" ")); // spacing
panel.add(new Label("Dialog parent:"));
@@ -123,6 +185,7 @@ public class PrintDialogsTest extends Applet implements ActionListener {
panel.add(cbHiddFrm);
panel.add(cbDlg);
panel.add(cbFrm);
panel.add(new Label(" ")); // spacing
panel.add(new Label("Dialog modality type:"));
groupModType = new CheckboxGroup();
@@ -139,7 +202,7 @@ public class PrintDialogsTest extends Applet implements ActionListener {
panel.add(cbDocModal);
panel.add(cbTKModal);
panel.add(cbModeless);
add(panel);
panel.add(new Label(" ")); // spacing
panel.add(new Label("Print dialog type:"));
groupDialog = new CheckboxGroup();
@@ -148,13 +211,6 @@ public class PrintDialogsTest extends Applet implements ActionListener {
panel.add(cbPage);
panel.add(cbPrint);
validate();
setVisible(true);
}
public void start() {
try {
EventQueue.invokeAndWait(this::createGUI);
} catch (Exception e) {}
add(panel);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2024, 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 8338139
* @summary Basic unit test of ClassLoadingMXBean.set/isVerbose() when
* related unified logging is enabled.
*
* @run main/othervm -Xlog:class+load=trace:file=vm.log TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=debug:file=vm.log TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=info:file=vm.log TestVerboseClassLoading false
*
* @run main/othervm -Xlog:class+load=trace TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=debug TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=info TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=warning TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=error TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load=off TestVerboseClassLoading false
*
* @run main/othervm -Xlog:class+load*=trace TestVerboseClassLoading true
* @run main/othervm -Xlog:class+load*=debug TestVerboseClassLoading true
* @run main/othervm -Xlog:class+load*=info TestVerboseClassLoading true
* @run main/othervm -Xlog:class+load*=warning TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load*=error TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load*=off TestVerboseClassLoading false
*
* @run main/othervm -Xlog:class+load*=info,class+load=trace TestVerboseClassLoading true
* @run main/othervm -Xlog:class+load*=info,class+load=debug TestVerboseClassLoading true
* @run main/othervm -Xlog:class+load*=info,class+load=info TestVerboseClassLoading true
* @run main/othervm -Xlog:class+load*=info,class+load=warning TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load*=info,class+load=error TestVerboseClassLoading false
* @run main/othervm -Xlog:class+load*=info,class+load=off TestVerboseClassLoading false
*
* @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseClassLoading false
*/
import java.lang.management.ManagementFactory;
import java.lang.management.ClassLoadingMXBean;
public class TestVerboseClassLoading {
public static void main(String[] args) throws Exception {
ClassLoadingMXBean mxBean = ManagementFactory.getClassLoadingMXBean();
boolean expected = Boolean.parseBoolean(args[0]);
boolean initial = mxBean.isVerbose();
if (expected != initial) {
throw new Error("Initial verbosity setting was unexpectedly " + initial);
}
mxBean.setVerbose(false);
if (mxBean.isVerbose()) {
throw new Error("Verbosity was still enabled");
}
mxBean.setVerbose(true);
if (!mxBean.isVerbose()) {
throw new Error("Verbosity was still disabled");
}
// Turn off again as a double-check and also to avoid excessive logging
mxBean.setVerbose(false);
if (mxBean.isVerbose()) {
throw new Error("Verbosity was still enabled");
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2024, 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 8338139
* @summary Basic unit test of TestVerboseMemory.set/isVerbose() when
* related unified logging is enabled.
*
* @run main/othervm -Xlog:gc=trace:file=vm.log TestVerboseMemory false
* @run main/othervm -Xlog:gc=debug:file=vm.log TestVerboseMemory false
* @run main/othervm -Xlog:gc=info:file=vm.log TestVerboseMemory false
*
* @run main/othervm -Xlog:gc=off TestVerboseMemory false
* @run main/othervm -Xlog:gc=error TestVerboseMemory false
* @run main/othervm -Xlog:gc=warning TestVerboseMemory false
*
* @run main/othervm -Xlog:gc=info TestVerboseMemory true
* @run main/othervm -Xlog:gc=trace TestVerboseMemory true
* @run main/othervm -Xlog:gc=debug TestVerboseMemory true
*
* @run main/othervm -Xlog:gc*=info TestVerboseMemory true
* @run main/othervm -Xlog:gc*=debug TestVerboseMemory true
* @run main/othervm -Xlog:gc*=trace TestVerboseMemory true
*
* @run main/othervm -Xlog:gc=info,gc+init=off TestVerboseMemory true
* @run main/othervm -Xlog:gc=off,gc+init=info TestVerboseMemory false
* @run main/othervm -Xlog:gc,gc+init TestVerboseMemory true
*
* @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseMemory false
*/
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
public class TestVerboseMemory {
public static void main(String[] args) throws Exception {
MemoryMXBean mxBean = ManagementFactory.getMemoryMXBean();
boolean expected = Boolean.parseBoolean(args[0]);
boolean initial = mxBean.isVerbose();
if (expected != initial) {
throw new Error("Initial verbosity setting was unexpectedly " + initial);
}
mxBean.setVerbose(false);
if (mxBean.isVerbose()) {
throw new Error("Verbosity was still enabled");
}
mxBean.setVerbose(true);
if (!mxBean.isVerbose()) {
throw new Error("Verbosity was still disabled");
}
// Turn off again as a double-check and also to avoid excessive logging
mxBean.setVerbose(false);
if (mxBean.isVerbose()) {
throw new Error("Verbosity was still enabled");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@@ -208,6 +208,7 @@ public interface HttpServerAdapters {
public abstract String getRequestMethod();
public abstract void close();
public abstract InetSocketAddress getRemoteAddress();
public abstract InetSocketAddress getLocalAddress();
public void serverPush(URI uri, HttpHeaders headers, byte[] body) {
ByteArrayInputStream bais = new ByteArrayInputStream(body);
serverPush(uri, headers, bais);
@@ -270,7 +271,10 @@ public interface HttpServerAdapters {
public InetSocketAddress getRemoteAddress() {
return exchange.getRemoteAddress();
}
@Override
public InetSocketAddress getLocalAddress() {
return exchange.getLocalAddress();
}
@Override
public URI getRequestURI() { return exchange.getRequestURI(); }
@Override
@@ -331,6 +335,10 @@ public interface HttpServerAdapters {
public InetSocketAddress getRemoteAddress() {
return exchange.getRemoteAddress();
}
@Override
public InetSocketAddress getLocalAddress() {
return exchange.getLocalAddress();
}
@Override
public URI getRequestURI() { return exchange.getRequestURI(); }

View File

@@ -23,6 +23,7 @@
/*
* @test
* @bug 8303965
* @modules java.base/sun.net.www.http
* java.net.http/jdk.internal.net.http.common
* java.net.http/jdk.internal.net.http.frame
@@ -201,20 +202,26 @@ public class BadHeadersTest {
// Assertions based on implementation specific detail messages. Keep in
// sync with implementation.
static void assertDetailMessage(Throwable throwable, int iterationIndex) {
assertTrue(throwable instanceof IOException,
"Expected IOException, got, " + throwable);
assertTrue(throwable.getMessage().contains("protocol error"),
"Expected \"protocol error\" in: " + throwable.getMessage());
try {
assertTrue(throwable instanceof IOException,
"Expected IOException, got, " + throwable);
assertTrue(throwable.getMessage().contains("malformed response"),
"Expected \"malformed response\" in: " + throwable.getMessage());
if (iterationIndex == 0) { // unknown
assertTrue(throwable.getMessage().contains("Unknown pseudo-header"),
"Expected \"Unknown pseudo-header\" in: " + throwable.getMessage());
} else if (iterationIndex == 4) { // unexpected
assertTrue(throwable.getMessage().contains(" Unexpected pseudo-header"),
"Expected \" Unexpected pseudo-header\" in: " + throwable.getMessage());
} else {
assertTrue(throwable.getMessage().contains("Bad header"),
"Expected \"Bad header\" in: " + throwable.getMessage());
if (iterationIndex == 0) { // unknown
assertTrue(throwable.getMessage().contains("Unknown pseudo-header"),
"Expected \"Unknown pseudo-header\" in: " + throwable.getMessage());
} else if (iterationIndex == 4) { // unexpected
assertTrue(throwable.getMessage().contains(" Unexpected pseudo-header"),
"Expected \" Unexpected pseudo-header\" in: " + throwable.getMessage());
} else {
assertTrue(throwable.getMessage().contains("Bad header"),
"Expected \"Bad header\" in: " + throwable.getMessage());
}
} catch (AssertionError e) {
System.out.println("Exception does not match expectation: " + throwable);
throwable.printStackTrace(System.out);
throw e;
}
}

View File

@@ -0,0 +1,362 @@
/*
* Copyright (c) 2022, 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 8263031
* @summary Tests that the HttpClient can correctly receive a Push Promise
* Frame with the END_HEADERS flag unset followed by one or more
* Continuation Frames.
* @library /test/lib server
* @build jdk.test.lib.net.SimpleSSLContext
* @modules java.base/sun.net.www.http
* java.net.http/jdk.internal.net.http.common
* java.net.http/jdk.internal.net.http.frame
* java.net.http/jdk.internal.net.http.hpack
* @run testng/othervm PushPromiseContinuation
*/
import jdk.internal.net.http.common.HttpHeadersBuilder;
import jdk.internal.net.http.frame.ContinuationFrame;
import jdk.internal.net.http.frame.HeaderFrame;
import org.testng.TestException;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import javax.net.ssl.SSLSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ProtocolException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiPredicate;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.testng.Assert.*;
public class PushPromiseContinuation {
static volatile HttpHeaders testHeaders;
static volatile HttpHeadersBuilder testHeadersBuilder;
static volatile int continuationCount;
static final String mainPromiseBody = "Main Promise Body";
static final String mainResponseBody = "Main Response Body";
Http2TestServer server;
URI uri;
// Set up simple client-side push promise handler
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<String>>> pushPromiseMap = new ConcurrentHashMap<>();
HttpResponse.PushPromiseHandler<String> pph = (initial, pushRequest, acceptor) -> {
HttpResponse.BodyHandler<String> s = HttpResponse.BodyHandlers.ofString(UTF_8);
pushPromiseMap.put(pushRequest, acceptor.apply(s));
};
@BeforeMethod
public void beforeMethod() {
pushPromiseMap = new ConcurrentHashMap<>();
}
@BeforeTest
public void setup() throws Exception {
server = new Http2TestServer(false, 0);
server.addHandler(new ServerPushHandler(), "/");
// Need to have a custom exchange supplier to manage the server's push
// promise with continuation flow
server.setExchangeSupplier(Http2PushPromiseContinuationExchangeImpl::new);
System.err.println("PushPromiseContinuation: Server listening on port " + server.getAddress().getPort());
server.start();
int port = server.getAddress().getPort();
uri = new URI("http://localhost:" + port + "/");
}
@AfterTest
public void teardown() {
pushPromiseMap = null;
server.stop();
}
/**
* Tests that when the client receives PushPromise Frame with the END_HEADERS
* flag set to 0x0 and subsequently receives a continuation frame, no exception
* is thrown and all headers from the PushPromise and Continuation Frames sent
* by the server arrive at the client.
*/
@Test
public void testOneContinuation() {
continuationCount = 1;
HttpClient client = HttpClient.newHttpClient();
// Carry out request
HttpRequest hreq = HttpRequest.newBuilder(uri).version(HttpClient.Version.HTTP_2).GET().build();
CompletableFuture<HttpResponse<String>> cf =
client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph);
HttpResponse<String> resp = cf.join();
// Verify results
verify(resp);
}
/**
* Same as above, but tests for the case where two Continuation Frames are sent
* with the END_HEADERS flag set only on the last frame.
*/
@Test
public void testTwoContinuations() {
continuationCount = 2;
HttpClient client = HttpClient.newHttpClient();
// Carry out request
HttpRequest hreq = HttpRequest.newBuilder(uri).version(HttpClient.Version.HTTP_2).GET().build();
CompletableFuture<HttpResponse<String>> cf =
client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph);
HttpResponse<String> resp = cf.join();
// Verify results
verify(resp);
}
@Test
public void testThreeContinuations() {
continuationCount = 3;
HttpClient client = HttpClient.newHttpClient();
// Carry out request
HttpRequest hreq = HttpRequest.newBuilder(uri).version(HttpClient.Version.HTTP_2).GET().build();
CompletableFuture<HttpResponse<String>> cf =
client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph);
HttpResponse<String> resp = cf.join();
// Verify results
verify(resp);
}
@Test
public void testSendHeadersOnPushPromiseStream() throws Exception {
// This test server sends a push promise that should be followed by a continuation but
// incorrectly sends on Response Headers while the client awaits the continuation.
Http2TestServer faultyServer = new Http2TestServer(false, 0);
faultyServer.addHandler(new ServerPushHandler(), "/");
faultyServer.setExchangeSupplier(Http2PushPromiseHeadersExchangeImpl::new);
System.err.println("PushPromiseContinuation: FaultyServer listening on port " + faultyServer.getAddress().getPort());
faultyServer.start();
int faultyPort = faultyServer.getAddress().getPort();
URI faultyUri = new URI("http://localhost:" + faultyPort + "/");
HttpClient client = HttpClient.newHttpClient();
// Server is making a request to an incorrect URI
HttpRequest hreq = HttpRequest.newBuilder(faultyUri).version(HttpClient.Version.HTTP_2).GET().build();
CompletableFuture<HttpResponse<String>> cf =
client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph);
CompletionException t = expectThrows(CompletionException.class, () -> cf.join());
assertEquals(t.getCause().getClass(), ProtocolException.class,
"Expected a ProtocolException but got " + t.getCause());
System.err.println("Client received the following expected exception: " + t.getCause());
faultyServer.stop();
}
private void verify(HttpResponse<String> resp) {
assertEquals(resp.statusCode(), 200);
assertEquals(resp.body(), mainResponseBody);
if (pushPromiseMap.size() > 1) {
System.err.println(pushPromiseMap.entrySet());
throw new TestException("Results map size is greater than 1");
} else {
// This will only iterate once
for (HttpRequest r : pushPromiseMap.keySet()) {
HttpResponse<String> serverPushResp = pushPromiseMap.get(r).join();
// Received headers should be the same as the combined PushPromise
// frame headers combined with the Continuation frame headers
assertEquals(testHeaders, r.headers());
// Check status code and push promise body are as expected
assertEquals(serverPushResp.statusCode(), 200);
assertEquals(serverPushResp.body(), mainPromiseBody);
}
}
}
static class Http2PushPromiseHeadersExchangeImpl extends Http2TestExchangeImpl {
Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders,
HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is,
SSLSession sslSession, BodyOutputStream os,
Http2TestServerConnection conn, boolean pushAllowed) {
super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed);
}
@Override
public void serverPush(URI uri, HttpHeaders headers, InputStream content) {
HttpHeadersBuilder headersBuilder = new HttpHeadersBuilder();
headersBuilder.setHeader(":method", "GET");
headersBuilder.setHeader(":scheme", uri.getScheme());
headersBuilder.setHeader(":authority", uri.getAuthority());
headersBuilder.setHeader(":path", uri.getPath());
for (Map.Entry<String,List<String>> entry : headers.map().entrySet()) {
for (String value : entry.getValue())
headersBuilder.addHeader(entry.getKey(), value);
}
HttpHeaders combinedHeaders = headersBuilder.build();
OutgoingPushPromise pp = new OutgoingPushPromise(streamid, uri, combinedHeaders, content);
// Indicates to the client that a continuation should be expected
pp.setFlag(0x0);
try {
conn.outputQ.put(pp);
// writeLoop will spin up thread to read the InputStream
} catch (IOException ex) {
System.err.println("TestServer: pushPromise exception: " + ex);
}
}
}
static class Http2PushPromiseContinuationExchangeImpl extends Http2TestExchangeImpl {
HttpHeadersBuilder pushPromiseHeadersBuilder;
List<ContinuationFrame> cfs;
Http2PushPromiseContinuationExchangeImpl(int streamid, String method, HttpHeaders reqheaders,
HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is,
SSLSession sslSession, BodyOutputStream os,
Http2TestServerConnection conn, boolean pushAllowed) {
super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed);
}
private void setPushHeaders(String name, String value) {
pushPromiseHeadersBuilder.setHeader(name, value);
testHeadersBuilder.setHeader(name, value);
}
private void assembleContinuations() {
for (int i = 0; i < continuationCount; i++) {
HttpHeadersBuilder builder = new HttpHeadersBuilder();
for (int j = 0; j < 10; j++) {
String name = "x-cont-" + i + "-" + j;
builder.setHeader(name, "data_" + j);
testHeadersBuilder.setHeader(name, "data_" + j);
}
ContinuationFrame cf = new ContinuationFrame(streamid, 0x0, conn.encodeHeaders(builder.build()));
// If this is the last Continuation Frame, set the END_HEADERS flag.
if (i >= continuationCount - 1) {
cf.setFlag(HeaderFrame.END_HEADERS);
}
cfs.add(cf);
}
}
@Override
public void serverPush(URI uri, HttpHeaders headers, InputStream content) {
pushPromiseHeadersBuilder = new HttpHeadersBuilder();
testHeadersBuilder = new HttpHeadersBuilder();
cfs = new ArrayList<>();
setPushHeaders(":method", "GET");
setPushHeaders(":scheme", uri.getScheme());
setPushHeaders(":authority", uri.getAuthority());
setPushHeaders(":path", uri.getPath());
for (Map.Entry<String,List<String>> entry : headers.map().entrySet()) {
for (String value : entry.getValue()) {
setPushHeaders(entry.getKey(), value);
}
}
for (int i = 0; i < 10; i++) {
setPushHeaders("x-push-header-" + i, "data_" + i);
}
// Create the Continuation Frame/s, done before Push Promise Frame for test purposes
// as testHeaders contains all headers used in all frames
assembleContinuations();
HttpHeaders pushPromiseHeaders = pushPromiseHeadersBuilder.build();
testHeaders = testHeadersBuilder.build();
// Create the Push Promise Frame
OutgoingPushPromise pp = new OutgoingPushPromise(streamid, uri, pushPromiseHeaders, content, cfs);
// Indicates to the client that a continuation should be expected
pp.setFlag(0x0);
try {
// Schedule push promise and continuation for sending
conn.outputQ.put(pp);
System.err.println("Server: Scheduled a Push Promise to Send");
} catch (IOException ex) {
System.err.println("Server: pushPromise exception: " + ex);
}
}
}
static class ServerPushHandler implements Http2Handler {
public void handle(Http2TestExchange exchange) throws IOException {
System.err.println("Server: handle " + exchange);
try (InputStream is = exchange.getRequestBody()) {
is.readAllBytes();
}
if (exchange.serverPushAllowed()) {
pushPromise(exchange);
}
// response data for the main response
try (OutputStream os = exchange.getResponseBody()) {
byte[] bytes = mainResponseBody.getBytes(UTF_8);
exchange.sendResponseHeaders(200, bytes.length);
os.write(bytes);
}
}
static final BiPredicate<String,String> ACCEPT_ALL = (x, y) -> true;
private void pushPromise(Http2TestExchange exchange) throws IOException {
URI requestURI = exchange.getRequestURI();
URI uri = requestURI.resolve("/promise");
InputStream is = new ByteArrayInputStream(mainPromiseBody.getBytes(UTF_8));
Map<String, List<String>> map = new HashMap<>();
map.put("x-promise", List.of("promise-header"));
HttpHeaders headers = HttpHeaders.of(map, ACCEPT_ALL);
exchange.serverPush(uri, headers, is);
System.err.println("Server: Push Promise complete");
}
}
}

View File

@@ -0,0 +1,324 @@
/*
* Copyright (c) 2023, 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
* @summary Trailing headers should be ignored by the client when using HTTP/2
* and not affect the rest of the exchange.
* @bug 8296410
* @library server
* @build Http2TestServer
* @modules java.base/sun.net.www.http
* java.net.http/jdk.internal.net.http.common
* java.net.http/jdk.internal.net.http.frame
* java.net.http/jdk.internal.net.http.hpack
* @run testng/othervm -Djdk.httpclient.HttpClient.log=all TrailingHeadersTest
*/
import jdk.internal.net.http.common.HttpHeadersBuilder;
import jdk.internal.net.http.frame.DataFrame;
import jdk.internal.net.http.frame.HeaderFrame;
import jdk.internal.net.http.frame.HeadersFrame;
import org.testng.TestException;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.net.ssl.SSLSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.function.BiPredicate;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.testng.Assert.assertEquals;
public class TrailingHeadersTest {
Http2TestServer http2TestServer;
URI trailingURI, trailng1xxURI, trailingPushPromiseURI, warmupURI;
static PrintStream testLog = System.err;
// Set up simple client-side push promise handler
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<String>>> pushPromiseMap = new ConcurrentHashMap<>();
@BeforeMethod
public void beforeMethod() {
pushPromiseMap = new ConcurrentHashMap<>();
}
@BeforeTest
public void setup() throws Exception {
Properties props = new Properties();
// For triggering trailing headers to send after Push Promise Response headers are sent
props.setProperty("sendTrailingHeadersAfterPushPromise", "1");
http2TestServer = new Http2TestServer("Test_Server",
false,
0,
null,
0,
props,
null);
http2TestServer.setExchangeSupplier(TrailingHeadersExchange::new);
http2TestServer.addHandler(new ResponseTrailersHandler(), "/ResponseTrailingHeaders");
http2TestServer.addHandler(new InformationalTrailersHandler(), "/InfoRespTrailingHeaders");
http2TestServer.addHandler(new PushPromiseTrailersHandler(), "/PushPromiseTrailingHeaders");
http2TestServer.addHandler(new WarmupHandler(), "/WarmupHandler");
http2TestServer.start();
trailingURI = URI.create("http://" + http2TestServer.serverAuthority() + "/ResponseTrailingHeaders");
trailng1xxURI = URI.create("http://" + http2TestServer.serverAuthority() + "/InfoRespTrailingHeaders");
trailingPushPromiseURI = URI.create("http://" + http2TestServer.serverAuthority() + "/PushPromiseTrailingHeaders");
// Used to ensure HTTP/2 upgrade takes place
warmupURI = URI.create("http://" + http2TestServer.serverAuthority() + "/WarmupHandler");
}
@AfterTest
public void teardown() {
http2TestServer.stop();
}
@Test(dataProvider = "httpRequests")
public void testTrailingHeaders(String description, HttpRequest hRequest, HttpResponse.PushPromiseHandler<String> pph) {
testLog.println("testTrailingHeaders(): " + description);
HttpClient httpClient = HttpClient.newBuilder().build();
performWarmupRequest(httpClient);
CompletableFuture<HttpResponse<String>> cf = httpClient.sendAsync(hRequest, BodyHandlers.ofString(UTF_8), pph);
testLog.println("testTrailingHeaders(): Performing request: " + hRequest);
HttpResponse<String> resp = cf.join();
assertEquals(resp.statusCode(), 200, "Status code of response should be 200");
// Verify Push Promise was successful if necessary
if (pph != null)
verifyPushPromise();
testLog.println("testTrailingHeaders(): Request successfully completed");
}
private void verifyPushPromise() {
assertEquals(pushPromiseMap.size(), 1, "Push Promise should not be greater than 1");
// This will only iterate once
for (HttpRequest r : pushPromiseMap.keySet()) {
CompletableFuture<HttpResponse<String>> serverPushResp = pushPromiseMap.get(r);
// Get the push promise HttpResponse result if present
HttpResponse<String> resp = serverPushResp.join();
assertEquals(resp.body(), "Sample_Push_Data", "Unexpected Push Promise response body");
assertEquals(resp.statusCode(), 200, "Status code of Push Promise response should be 200");
}
}
private void performWarmupRequest(HttpClient httpClient) {
HttpRequest warmupReq = HttpRequest.newBuilder(warmupURI).version(HTTP_2)
.GET()
.build();
httpClient.sendAsync(warmupReq, BodyHandlers.discarding()).join();
}
@DataProvider(name = "httpRequests")
public Object[][] uris() {
HttpResponse.PushPromiseHandler<String> pph = (initial, pushRequest, acceptor) -> {
HttpResponse.BodyHandler<String> s = HttpResponse.BodyHandlers.ofString(UTF_8);
pushPromiseMap.put(pushRequest, acceptor.apply(s));
};
HttpRequest httpGetTrailing = HttpRequest.newBuilder(trailingURI).version(HTTP_2)
.GET()
.build();
HttpRequest httpPost1xxTrailing = HttpRequest.newBuilder(trailng1xxURI).version(HTTP_2)
.POST(HttpRequest.BodyPublishers.ofString("Test Post"))
.expectContinue(true)
.build();
HttpRequest httpGetPushPromiseTrailing = HttpRequest.newBuilder(trailingPushPromiseURI).version(HTTP_2)
.GET()
.build();
return new Object[][] {
{ "Test GET with Trailing Headers", httpGetTrailing, null },
{ "Test POST with 1xx response & Trailing Headers", httpPost1xxTrailing, null },
{ "Test Push Promise with Trailing Headers", httpGetPushPromiseTrailing, pph }
};
}
static class TrailingHeadersExchange extends Http2TestExchangeImpl {
byte[] resp = "Sample_Data".getBytes(StandardCharsets.UTF_8);
TrailingHeadersExchange(int streamid, String method, HttpHeaders reqheaders, HttpHeadersBuilder rspheadersBuilder,
URI uri, InputStream is, SSLSession sslSession, BodyOutputStream os,
Http2TestServerConnection conn, boolean pushAllowed) {
super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed);
}
public void sendResponseThenTrailers() throws IOException {
/*
HttpHeadersBuilder hb = this.conn.createNewHeadersBuilder();
hb.setHeader("x-sample", "val");
HeaderFrame headerFrame = new HeadersFrame(this.streamid, 0, this.conn.encodeHeaders(hb.build()));
*/
// TODO: see if there is a safe way to encode headers without interrupting connection thread
HeaderFrame headerFrame = new HeadersFrame(this.streamid, 0, List.of());
headerFrame.setFlag(HeaderFrame.END_HEADERS);
headerFrame.setFlag(HeaderFrame.END_STREAM);
this.sendResponseHeaders(200, resp.length);
DataFrame dataFrame = new DataFrame(this.streamid, 0, ByteBuffer.wrap(resp));
this.conn.addToOutputQ(dataFrame);
this.conn.addToOutputQ(headerFrame);
}
@Override
public void serverPush(URI uri, HttpHeaders headers, InputStream content) {
HttpHeadersBuilder headersBuilder = new HttpHeadersBuilder();
headersBuilder.setHeader(":method", "GET");
headersBuilder.setHeader(":scheme", uri.getScheme());
headersBuilder.setHeader(":authority", uri.getAuthority());
headersBuilder.setHeader(":path", uri.getPath());
for (Map.Entry<String,List<String>> entry : headers.map().entrySet()) {
for (String value : entry.getValue())
headersBuilder.addHeader(entry.getKey(), value);
}
HttpHeaders combinedHeaders = headersBuilder.build();
OutgoingPushPromise pp = new OutgoingPushPromise(streamid, uri, combinedHeaders, content);
pp.setFlag(HeaderFrame.END_HEADERS);
try {
this.conn.addToOutputQ(pp);
} catch (IOException ex) {
testLog.println("serverPush(): pushPromise exception: " + ex);
}
}
}
static class WarmupHandler implements Http2Handler {
@Override
public void handle(Http2TestExchange exchange) throws IOException {
exchange.sendResponseHeaders(200, 0);
}
}
static class ResponseTrailersHandler implements Http2Handler {
@Override
public void handle(Http2TestExchange exchange) throws IOException {
if (exchange.getProtocol().equals("HTTP/2")) {
if (exchange instanceof TrailingHeadersExchange) {
TrailingHeadersExchange trailingHeadersExchange = (TrailingHeadersExchange)exchange;
trailingHeadersExchange.sendResponseThenTrailers();
}
} else {
testLog.println("ResponseTrailersHandler: Incorrect protocol version");
exchange.sendResponseHeaders(400, 0);
}
}
}
static class InformationalTrailersHandler implements Http2Handler {
@Override
public void handle(Http2TestExchange exchange) throws IOException {
if (exchange.getProtocol().equals("HTTP/2")) {
if (exchange instanceof TrailingHeadersExchange) {
TrailingHeadersExchange trailingHeadersExchange = (TrailingHeadersExchange)exchange;
testLog.println(this.getClass().getCanonicalName() + ": Sending status 100");
trailingHeadersExchange.sendResponseHeaders(100, 0);
try (InputStream is = exchange.getRequestBody()) {
is.readAllBytes();
trailingHeadersExchange.sendResponseThenTrailers();
}
}
} else {
testLog.println("InformationalTrailersHandler: Incorrect protocol version");
exchange.sendResponseHeaders(400, 0);
}
}
}
static class PushPromiseTrailersHandler implements Http2Handler {
@Override
public void handle(Http2TestExchange exchange) throws IOException {
if (exchange.getProtocol().equals("HTTP/2")) {
if (exchange instanceof TrailingHeadersExchange) {
TrailingHeadersExchange trailingHeadersExchange = (TrailingHeadersExchange)exchange;
try (InputStream is = exchange.getRequestBody()) {
is.readAllBytes();
}
if (exchange.serverPushAllowed()) {
pushPromise(trailingHeadersExchange);
}
try (OutputStream os = trailingHeadersExchange.getResponseBody()) {
byte[] bytes = "Sample_Data".getBytes(UTF_8);
trailingHeadersExchange.sendResponseHeaders(200, bytes.length);
os.write(bytes);
}
}
}
}
static final BiPredicate<String,String> ACCEPT_ALL = (x, y) -> true;
private void pushPromise(Http2TestExchange exchange) {
URI requestURI = exchange.getRequestURI();
URI uri = requestURI.resolve("/promise");
InputStream is = new ByteArrayInputStream("Sample_Push_Data".getBytes(UTF_8));
Map<String, List<String>> map = new HashMap<>();
map.put("x-promise", List.of("promise-header"));
HttpHeaders headers = HttpHeaders.of(map, ACCEPT_ALL);
exchange.serverPush(uri, headers, is);
testLog.println("PushPromiseTrailersHandler: Push Promise complete");
}
}
}

View File

@@ -128,10 +128,14 @@ class BodyOutputStream extends OutputStream {
closed = true;
}
try {
send(EMPTY_BARRAY, 0, 0, DataFrame.END_STREAM);
sendEndStream();
} catch (IOException ex) {
System.err.println("TestServer: OutputStream.close exception: " + ex);
ex.printStackTrace();
}
}
protected void sendEndStream() throws IOException {
send(EMPTY_BARRAY, 0, 0, DataFrame.END_STREAM);
}
}

Some files were not shown because too many files have changed in this diff Show More