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

io.datakernel.http.AcceptCharset Maven / Gradle / Ivy

/*
 * Copyright (C) 2015-2018 SoftIndex LLC.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.datakernel.http;

import io.datakernel.bytebuf.ByteBuf;
import io.datakernel.exception.ParseException;

import java.nio.charset.Charset;
import java.util.List;

import static io.datakernel.bytebuf.ByteBufStrings.*;
import static io.datakernel.http.HttpUtils.parseQ;
import static io.datakernel.http.HttpUtils.skipSpaces;
import static io.datakernel.util.Preconditions.checkArgument;

/**
 * This is a value class for the Accept-Charset header value.
 */
public final class AcceptCharset {
	public static final int DEFAULT_Q = 100;
	private static final byte[] Q_KEY = encodeAscii("q");

	private HttpCharset charset;
	private int q;

	private AcceptCharset(HttpCharset charset, int q) {
		this.charset = charset;
		this.q = q;
	}

	private AcceptCharset(HttpCharset charset) {
		this(charset, DEFAULT_Q);
	}

	public static AcceptCharset of(Charset charset) {
		return new AcceptCharset(HttpCharset.of(charset));
	}

	public static AcceptCharset of(Charset charset, int q) {
		checkArgument(q >= 0 && q <= 100, "Cannot create AcceptCharset with 'q' that is outside of bounds [0, 100]");
		return new AcceptCharset(HttpCharset.of(charset), q);
	}

	private static AcceptCharset of(HttpCharset charset) {
		return new AcceptCharset(charset);
	}

	private static AcceptCharset of(HttpCharset charset, int q) {
		return new AcceptCharset(charset, q);
	}

	public Charset getCharset() throws ParseException {
		return charset.toJavaCharset();
	}

	public int getQ() {
		return q;
	}

	static void parse(byte[] bytes, int pos, int len, List list) throws ParseException {
		try {
			int end = pos + len;

			while (pos < end) {
				// parsing charset
				pos = skipSpaces(bytes, pos, end);
				int start = pos;
				while (pos < end && !(bytes[pos] == ';' || bytes[pos] == ',')) {
					pos++;
				}
				HttpCharset charset = HttpCharset.parse(bytes, start, pos - start);

				if (pos < end) {
					if (bytes[pos++] == ',') {
						list.add(AcceptCharset.of(charset));
					} else {
						int q = DEFAULT_Q;
						pos = skipSpaces(bytes, pos, end);
						start = pos;
						while (pos < end && bytes[pos] != ',') {
							if (bytes[pos] == '=' && equalsLowerCaseAscii(Q_KEY, bytes, start, pos - start)) {
								start = ++pos;
								while (pos < end && !(bytes[pos] == ';' || bytes[pos] == ',')) {
									pos++;
								}
								q = parseQ(bytes, start, pos - start);
								pos--;
							} else if (bytes[pos] == ';') {
								pos = skipSpaces(bytes, pos + 1, end);
								start = pos;
							}
							pos++;
						}
						list.add(AcceptCharset.of(charset, q));
						pos++;
					}
				} else {
					list.add(AcceptCharset.of(charset));
				}
			}
		} catch (RuntimeException e) {
			throw new ParseException(AcceptCharset.class, "Failed to parse accept-charset", e);
		}
	}

	static void render(List charsets, ByteBuf buf) {
		int pos = render(charsets, buf.array(), buf.tail());
		buf.tail(pos);
	}

	static int render(List charsets, byte[] bytes, int pos) {
		for (int i = 0; i < charsets.size(); i++) {
			AcceptCharset charset = charsets.get(i);
			pos += HttpCharset.render(charset.charset, bytes, pos);
			if (charset.q != DEFAULT_Q) {
				bytes[pos++] = ';';
				bytes[pos++] = ' ';
				bytes[pos++] = 'q';
				bytes[pos++] = '=';
				bytes[pos++] = '0';
				bytes[pos++] = '.';
				int q = charset.q;
				if (q % 10 == 0) q /= 10;
				pos += encodePositiveInt(bytes, pos, q);
			}
			if (i < charsets.size() - 1) {
				bytes[pos++] = ',';
				bytes[pos++] = ' ';
			}
		}
		return pos;
	}

	int estimateSize() {
		return charset.size() + 10;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		AcceptCharset that = (AcceptCharset) o;

		if (q != that.q) return false;
		return charset.equals(that.charset);
	}

	@Override
	public int hashCode() {
		int result = charset.hashCode();
		result = 31 * result + q;
		return result;
	}

	@Override
	public String toString() {
		return "AcceptCharset{charset=" + charset + ", q=" + q + '}';
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy