All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.http.MutableHttpFields Maven / Gradle / Ivy

There is a newer version: 12.1.0.alpha0
Show newest version
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.http;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.stream.Stream;

/**
 * HTTP Fields. A collection of HTTP header and or Trailer fields.
 *
 * 

This class is not synchronized as it is expected that modifications will only be performed by a * single thread. * *

The cookie handling provided by this class is guided by the Servlet specification and RFC6265. */ class MutableHttpFields implements HttpFields.Mutable { private static final int INITIAL_SIZE = 16; private static final int SIZE_INCREMENT = 4; private HttpField[] _fields; private boolean _immutable; private int _size; /** * Initialize an empty HttpFields. */ protected MutableHttpFields() { this(INITIAL_SIZE); // Based on small sample of Chrome requests. } /** * Initialize an empty HttpFields. * * @param capacity the capacity of the http fields */ protected MutableHttpFields(int capacity) { _fields = new HttpField[capacity]; } /** * Initialize HttpFields from another. * * @param fields the fields to copy data from */ protected MutableHttpFields(HttpFields fields) { if (fields instanceof org.eclipse.jetty.http.ImmutableHttpFields immutable) { _immutable = true; _fields = immutable._fields; _size = immutable._size; } else if (fields != null) { _fields = new HttpField[fields.size() + SIZE_INCREMENT]; add(fields); } else { _fields = new HttpField[INITIAL_SIZE]; } } /** * Initialize HttpFields from another and replace a field * * @param fields the fields to copy data from * @param replaceField the replacement field */ protected MutableHttpFields(HttpFields fields, HttpField replaceField) { _fields = new HttpField[fields.size() + SIZE_INCREMENT]; _size = 0; boolean put = false; for (HttpField f : fields) { if (replaceField.isSameName(f)) { if (!put) _fields[_size++] = replaceField; put = true; } else { _fields[_size++] = f; } } if (!put) _fields[_size++] = replaceField; } /** * Initialize HttpFields from another and remove fields * * @param fields the fields to copy data from * @param removeFields the the fields to remove */ protected MutableHttpFields(HttpFields fields, EnumSet removeFields) { _fields = new HttpField[fields.size() + SIZE_INCREMENT]; _size = 0; for (HttpField f : fields) { if (f.getHeader() == null || !removeFields.contains(f.getHeader())) _fields[_size++] = f; } } @Override public Mutable add(HttpField field) { if (field != null) { if (_immutable || _size == _fields.length) { _immutable = false; _fields = Arrays.copyOf(_fields, _size + SIZE_INCREMENT); } _fields[_size++] = field; } return this; } @Override public Mutable add(HttpFields fields) { if (fields.size() == 0) return this; if (_immutable || _size + fields.size() >= _fields.length) { _immutable = false; _fields = Arrays.copyOf(_fields, _size + fields.size() + SIZE_INCREMENT); } if (fields instanceof org.eclipse.jetty.http.ImmutableHttpFields immutable) { System.arraycopy(immutable._fields, 0, _fields, _size, immutable._size); _size += immutable._size; } else if (fields instanceof org.eclipse.jetty.http.MutableHttpFields mutable) { System.arraycopy(mutable._fields, 0, _fields, _size, mutable._size); _size += mutable._size; } else { for (HttpField f : fields) { _fields[_size++] = f; } } return this; } @Override public HttpFields asImmutable() { _immutable = true; return new org.eclipse.jetty.http.ImmutableHttpFields(_fields, _size); } private void copyImmutable() { if (_immutable) { _immutable = false; _fields = Arrays.copyOf(_fields, _fields.length); } } @Override public Mutable clear() { if (_immutable) { _fields = new HttpField[_fields.length]; _immutable = false; } _size = 0; return this; } @Override public int hashCode() { int hash = 2099; // prime for (int i = _size; i-- > 0; ) { HttpField field = _fields[i]; if (field != null) hash ^= field.hashCode(); } return hash; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof org.eclipse.jetty.http.MutableHttpFields)) return false; return isEqualTo((HttpFields)o); } /** * Get a Field by index. * * @param index the field index * @return A Field value or null if the Field value has not been set */ @Override public HttpField getField(int index) { if (index >= _size || index < 0) throw new NoSuchElementException(); return _fields[index]; } @Override public HttpField getField(HttpHeader header) { // default impl overridden for efficiency for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (f != null && f.getHeader() == header) return f; } return null; } @Override public HttpField getField(String name) { // default impl overridden for efficiency for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (f != null && f.is(name)) return f; } return null; } @Override public Iterator iterator() { return new Iterator<>() { int _index = 0; @Override public boolean hasNext() { return _index < _size; } @Override public HttpField next() { return _fields[_index++]; } @Override public void remove() { if (_size == 0) throw new IllegalStateException(); org.eclipse.jetty.http.MutableHttpFields.this.remove(--_index); } }; } @Override public ListIterator listIterator() { return listIterator(0); } @Override public ListIterator listIterator(int index) { copyImmutable(); return new Listerator(index); } @Override public Mutable put(HttpField field) { copyImmutable(); boolean put = false; for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (f.isSameName(field)) { if (put) System.arraycopy(_fields, i + 1, _fields, i, _size-- - i-- - 1); else { _fields[i] = field; put = true; } } } if (!put) add(field); return this; } @Override public Mutable put(String name, String value) { return (value == null) ? remove(name) : put(new HttpField(name, value)); } @Override public Mutable put(HttpHeader header, HttpHeaderValue value) { return put(header, value.toString()); } @Override public Mutable put(HttpHeader header, String value) { return (value == null) ? remove(header) : put(new HttpField(header, value)); } @Override public Mutable computeField(HttpHeader header, BiFunction, HttpField> computeFn) { return computeField(header, computeFn, (f, h) -> f.getHeader() == h); } @Override public Mutable computeField(String name, BiFunction, HttpField> computeFn) { return computeField(name, computeFn, HttpField::is); } public Mutable computeField(T header, BiFunction, HttpField> computeFn, BiPredicate matcher) { copyImmutable(); // Look for first occurrence int first = -1; for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (matcher.test(f, header)) { first = i; break; } } // If the header is not found, add a new one; if (first < 0) { HttpField newField = computeFn.apply(header, null); if (newField != null) add(newField); return this; } // Are there any more occurrences? List found = null; for (int i = first + 1; i < _size; i++) { HttpField f = _fields[i]; if (matcher.test(f, header)) { if (found == null) { found = new ArrayList<>(); found.add(_fields[first]); } // Remember and remove additional fields found.add(f); remove(i--); } } // If no additional fields were found, handle singleton case if (found == null) found = Collections.singletonList(_fields[first]); else found = Collections.unmodifiableList(found); HttpField newField = computeFn.apply(header, found); if (newField == null) remove(first); else _fields[first] = newField; return this; } @Override public Mutable remove(HttpHeader name) { for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (f.getHeader() == name) remove(i--); } return this; } @Override public Mutable remove(EnumSet headers) { for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (headers.contains(f.getHeader())) remove(i--); } return this; } @Override public Mutable remove(String name) { for (int i = 0; i < _size; i++) { HttpField f = _fields[i]; if (f.is(name)) remove(i--); } return this; } private void remove(int i) { _size--; if (_immutable) { _immutable = false; HttpField[] fields = _fields; _fields = new HttpField[fields.length]; System.arraycopy(fields, 0, _fields, 0, i); System.arraycopy(fields, i + 1, _fields, i, _size - i); } else { System.arraycopy(_fields, i + 1, _fields, i, _size - i); } _fields[_size] = null; } public int size() { return _size; } @Override public Stream stream() { return Arrays.stream(_fields, 0, _size); } @Override public String toString() { return asString(); } private class Listerator implements ListIterator { private int _index; private int _last = -1; Listerator(int index) { if (index < 0 || index > _size) throw new NoSuchElementException(Integer.toString(index)); _index = index; } @Override public void add(HttpField field) { if (field == null) return; int last = _size++; if (_fields.length < _size) _fields = Arrays.copyOf(_fields, _fields.length + SIZE_INCREMENT); System.arraycopy(_fields, _index, _fields, _index + 1, last - _index); _fields[_index++] = field; _last = -1; } @Override public boolean hasNext() { return _index < _size; } @Override public boolean hasPrevious() { return _index > 0; } @Override public HttpField next() { if (_index >= _size) throw new NoSuchElementException(Integer.toString(_index)); _last = _index++; return _fields[_last]; } @Override public int nextIndex() { return _index + 1; } @Override public HttpField previous() { if (_index <= 0) throw new NoSuchElementException(Integer.toString(_index - 1)); _last = --_index; return _fields[_last]; } @Override public int previousIndex() { return _index - 1; } @Override public void remove() { if (_last < 0) throw new IllegalStateException(); org.eclipse.jetty.http.MutableHttpFields.this.remove(_last); _index = _last; _last = -1; } @Override public void set(HttpField field) { if (_last < 0) throw new IllegalStateException(); if (field == null) remove(); else _fields[_last] = field; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy