1 /* 2 * ==================================================================== 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * ==================================================================== 20 * 21 * This software consists of voluntary contributions made by many 22 * individuals on behalf of the Apache Software Foundation. For more 23 * information on the Apache Software Foundation, please see 24 * <http://www.apache.org/>. 25 * 26 */ 27 28 package org.apache.hc.core5.http.impl.nio; 29 30 import java.io.IOException; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.ReadableByteChannel; 33 import java.util.List; 34 35 import org.apache.hc.core5.http.Header; 36 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics; 37 import org.apache.hc.core5.http.nio.ContentDecoder; 38 import org.apache.hc.core5.http.nio.SessionInputBuffer; 39 import org.apache.hc.core5.util.Args; 40 41 /** 42 * Abstract {@link ContentDecoder} that serves as a base for all content 43 * decoder implementations. 44 * 45 * @since 4.0 46 */ 47 public abstract class AbstractContentDecoder implements ContentDecoder { 48 49 final ReadableByteChannel channel; 50 final SessionInputBuffer buffer; 51 final BasicHttpTransportMetrics metrics; 52 53 protected boolean completed; 54 55 /** 56 * Creates an instance of this class. 57 * 58 * @param channel the source channel. 59 * @param buffer the session input buffer that can be used to store 60 * session data for intermediate processing. 61 * @param metrics Transport metrics of the underlying HTTP transport. 62 */ 63 public AbstractContentDecoder( 64 final ReadableByteChannel channel, 65 final SessionInputBuffer buffer, 66 final BasicHttpTransportMetrics metrics) { 67 super(); 68 Args.notNull(channel, "Channel"); 69 Args.notNull(buffer, "Session input buffer"); 70 Args.notNull(metrics, "Transport metrics"); 71 this.buffer = buffer; 72 this.channel = channel; 73 this.metrics = metrics; 74 } 75 76 protected ReadableByteChannel channel() { 77 return this.channel; 78 } 79 80 protected SessionInputBuffer buffer() { 81 return this.buffer; 82 } 83 84 protected BasicHttpTransportMetrics metrics() { 85 return this.metrics; 86 } 87 88 @Override 89 public boolean isCompleted() { 90 return this.completed; 91 } 92 93 /** 94 * Sets the completed status of this decoder. Normally this is not necessary 95 * (the decoder will automatically complete when the underlying channel 96 * returns EOF). It is useful to mark the decoder as completed if you have 97 * some other means to know all the necessary data has been read and want to 98 * reuse the underlying connection for more messages. 99 * 100 * @param completed the completed status of this decoder. 101 * @since 4.4.11 102 */ 103 public void setCompleted(final boolean completed) { 104 this.completed = completed; 105 } 106 107 /** 108 * Sets the completed status of this decoder to true. Normally this is not necessary 109 * (the decoder will automatically complete when the underlying channel 110 * returns EOF). It is useful to mark the decoder as completed if you have 111 * some other means to know all the necessary data has been read and want to 112 * reuse the underlying connection for more messages. 113 * 114 * @since 4.4.11 115 */ 116 protected void setCompleted() { 117 this.completed = true; 118 } 119 120 /** 121 * Reads from the channel to the destination. 122 * 123 * @param dst destination. 124 * @return number of bytes transferred. 125 * @throws IOException If an I/O error occurs. 126 * 127 * @since 4.3 128 */ 129 protected int readFromChannel(final ByteBuffer dst) throws IOException { 130 final int bytesRead = this.channel.read(dst); 131 if (bytesRead > 0) { 132 this.metrics.incrementBytesTransferred(bytesRead); 133 } 134 return bytesRead; 135 } 136 137 /** 138 * Reads from the channel to the session buffer. 139 * 140 * @return number of bytes transferred, possibly zero, or {@code -1} if the channel has reached end-of-stream. 141 * @throws IOException If an I/O error occurs. 142 * 143 * @since 4.3 144 */ 145 protected int fillBufferFromChannel() throws IOException { 146 final int bytesRead = this.buffer.fill(this.channel); 147 if (bytesRead > 0) { 148 this.metrics.incrementBytesTransferred(bytesRead); 149 } 150 return bytesRead; 151 } 152 153 /** 154 * Reads from the channel to the destination. 155 * 156 * @param dst destination. 157 * @param limit max number of bytes to transfer. 158 * @return number of bytes transferred, possibly zero, or {@code -1} if the channel has reached end-of-stream. 159 * @throws IOException If an I/O error occurs. 160 * 161 * @since 4.3 162 */ 163 protected int readFromChannel(final ByteBuffer dst, final int limit) throws IOException { 164 final int bytesRead; 165 if (dst.remaining() > limit) { 166 final int oldLimit = dst.limit(); 167 final int newLimit = oldLimit - (dst.remaining() - limit); 168 dst.limit(newLimit); 169 bytesRead = this.channel.read(dst); 170 dst.limit(oldLimit); 171 } else { 172 bytesRead = this.channel.read(dst); 173 } 174 if (bytesRead > 0) { 175 this.metrics.incrementBytesTransferred(bytesRead); 176 } 177 return bytesRead; 178 } 179 180 @Override 181 public List<? extends Header> getTrailers() { 182 return null; 183 } 184 185 }