/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.undertow.server.handlers.form;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import io.undertow.UndertowMessages;
import io.undertow.util.HeaderMap;

Representation of form data.

TODO: add representation of multipart data

/** * Representation of form data. * <p> * TODO: add representation of multipart data */
public final class FormData implements Iterable<String> { private final Map<String, Deque<FormValue>> values = new LinkedHashMap<>(); private final int maxValues; private int valueCount = 0; public FormData(final int maxValues) { this.maxValues = maxValues; } public Iterator<String> iterator() { return values.keySet().iterator(); } public FormValue getFirst(String name) { final Deque<FormValue> deque = values.get(name); return deque == null ? null : deque.peekFirst(); } public FormValue getLast(String name) { final Deque<FormValue> deque = values.get(name); return deque == null ? null : deque.peekLast(); } public Deque<FormValue> get(String name) { return values.get(name); } public void add(String name, String value) { add(name, value, null); } public void add(String name, String value, final HeaderMap headers) { Deque<FormValue> values = this.values.get(name); if (values == null) { this.values.put(name, values = new ArrayDeque<>(1)); } values.add(new FormValueImpl(value, headers)); if (++valueCount > maxValues) { throw new RuntimeException(UndertowMessages.MESSAGES.tooManyParameters(maxValues)); } } public void add(String name, Path value, String fileName, final HeaderMap headers) { Deque<FormValue> values = this.values.get(name); if (values == null) { this.values.put(name, values = new ArrayDeque<>(1)); } values.add(new FormValueImpl(value, fileName, headers)); if (values.size() > maxValues) { throw new RuntimeException(UndertowMessages.MESSAGES.tooManyParameters(maxValues)); } if (++valueCount > maxValues) { throw new RuntimeException(UndertowMessages.MESSAGES.tooManyParameters(maxValues)); } } public void put(String name, String value, final HeaderMap headers) { Deque<FormValue> values = new ArrayDeque<>(1); Deque<FormValue> old = this.values.put(name, values); if (old != null) { valueCount -= old.size(); } values.add(new FormValueImpl(value, headers)); if (++valueCount > maxValues) { throw new RuntimeException(UndertowMessages.MESSAGES.tooManyParameters(maxValues)); } } public Deque<FormValue> remove(String name) { Deque<FormValue> old = values.remove(name); if (old != null) { valueCount -= old.size(); } return old; } public boolean contains(String name) { final Deque<FormValue> value = values.get(name); return value != null && !value.isEmpty(); } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final FormData strings = (FormData) o; if (values != null ? !values.equals(strings.values) : strings.values != null) return false; return true; } @Override public int hashCode() { return values != null ? values.hashCode() : 0; } @Override public String toString() { return "FormData{" + "values=" + values + '}'; } public interface FormValue {
Throws:
Returns:the simple string value.
/** * @return the simple string value. * @throws IllegalStateException If this is not a simple string value */
String getValue();
Returns true if this is a file and not a simple string
Returns:
/** * Returns true if this is a file and not a simple string * * @return */
boolean isFile();
Throws:
Returns:The temp file that the file data was saved to
/** * @return The temp file that the file data was saved to * @throws IllegalStateException if this is not a file */
Path getPath(); @Deprecated File getFile();
Returns:The filename specified in the disposition header.
/** * @return The filename specified in the disposition header. */
String getFileName();
Returns:The headers that were present in the multipart request, or null if this was not a multipart request
/** * @return The headers that were present in the multipart request, or null if this was not a multipart request */
HeaderMap getHeaders(); } static class FormValueImpl implements FormValue { private final String value; private final String fileName; private final Path file; private final HeaderMap headers; FormValueImpl(String value, HeaderMap headers) { this.value = value; this.headers = headers; this.file = null; this.fileName = null; } FormValueImpl(Path file, final String fileName, HeaderMap headers) { this.file = file; this.headers = headers; this.fileName = fileName; this.value = null; } @Override public String getValue() { if (value == null) { throw UndertowMessages.MESSAGES.formValueIsAFile(); } return value; } @Override public boolean isFile() { return file != null; } @Override public Path getPath() { if (file == null) { throw UndertowMessages.MESSAGES.formValueIsAString(); } return file; } @Override public File getFile() { return getPath().toFile(); } @Override public HeaderMap getHeaders() { return headers; } public String getFileName() { return fileName; } } }