1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.libraries.entitlement.http; 18 19 import static com.android.libraries.entitlement.utils.DebugUtils.logPii; 20 21 import com.google.common.collect.ImmutableList; 22 23 import java.net.HttpCookie; 24 import java.util.List; 25 26 /** 27 * Simple cookie management. 28 * 29 * <p>Use {@link #parseSetCookieHeaders} to parse the "Set-Cookie" headers in HTTP responses 30 * from the server, and use {@link #toCookieHeaders} to generate the "Cookie" headers in 31 * follow-up HTTP requests. 32 */ 33 public class HttpCookieJar { 34 private final ImmutableList<HttpCookie> mCookies; 35 HttpCookieJar(ImmutableList<HttpCookie> cookies)36 private HttpCookieJar(ImmutableList<HttpCookie> cookies) { 37 mCookies = cookies; 38 } 39 40 /** 41 * Parses the "Set-Cookie" headers in HTTP responses from servers. 42 */ parseSetCookieHeaders(List<String> rawCookies)43 public static HttpCookieJar parseSetCookieHeaders(List<String> rawCookies) { 44 ImmutableList.Builder<HttpCookie> parsedCookies = ImmutableList.builder(); 45 for (String rawCookie : rawCookies) { 46 List<HttpCookie> cookies = parseCookiesSafely(rawCookie); 47 parsedCookies.addAll(cookies); 48 } 49 return new HttpCookieJar(parsedCookies.build()); 50 } 51 52 /** 53 * Returns the cookies as "Cookie" headers in HTTP requests to servers. 54 */ toCookieHeaders()55 public ImmutableList<String> toCookieHeaders() { 56 ImmutableList.Builder<String> cookieHeader = ImmutableList.builder(); 57 for (HttpCookie cookie : mCookies) { 58 cookieHeader.add(removeObsoleteCookieAttributes(cookie).toString()); 59 } 60 return cookieHeader.build(); 61 } 62 parseCookiesSafely(String rawCookie)63 private static List<HttpCookie> parseCookiesSafely(String rawCookie) { 64 try { 65 return HttpCookie.parse(rawCookie); 66 } catch (IllegalArgumentException e) { 67 logPii("Failed to parse cookie: " + rawCookie); 68 return ImmutableList.of(); 69 } 70 } 71 72 /** 73 * Removes some attributes of the cookie that should not be set in HTTP requests. 74 * 75 * <p>Unfortunately, {@link HttpCookie#toString()} preserves some cookie attributes: 76 * Domain, Path, and Port as per RFC 2965. Such behavior is obsoleted by the RFC 6265. 77 * 78 * <p>To be clear, Domain and Path are valid attributes by RFC 6265, but cookie attributes 79 * be set in HTTP request "Cookie" headers. 80 */ removeObsoleteCookieAttributes(HttpCookie cookie)81 private static HttpCookie removeObsoleteCookieAttributes(HttpCookie cookie) { 82 cookie.setDomain(null); 83 cookie.setPath(null); 84 cookie.setPortlist(null); 85 return cookie; 86 } 87 } 88