1 //
2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.io.BufferedInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.nio.charset.StandardCharsets;
25
26 /**
27 * ReadLineInputStream
28 *
29 * Read from an input stream, accepting CR/LF, LF or just CR.
30 */
31 public class ReadLineInputStream extends BufferedInputStream
32 {
33 boolean _seenCRLF;
34 boolean _skipLF;
35
36 public ReadLineInputStream(InputStream in)
37 {
38 super(in);
39 }
40
41 public ReadLineInputStream(InputStream in, int size)
42 {
43 super(in,size);
44 }
45
46 public String readLine() throws IOException
47 {
48 mark(buf.length);
49
50 while (true)
51 {
52 int b=super.read();
53
54 if (markpos < 0)
55 throw new IOException("Buffer size exceeded: no line terminator");
56
57 if (b==-1)
58 {
59 int m=markpos;
60 markpos=-1;
61 if (pos>m)
62 return new String(buf,m,pos-m, StandardCharsets.UTF_8);
63
64 return null;
65 }
66
67 if (b=='\r')
68 {
69 int p=pos;
70
71 // if we have seen CRLF before, hungrily consume LF
72 if (_seenCRLF && pos<count)
73 {
74 if (buf[pos]=='\n')
75 pos+=1;
76 }
77 else
78 _skipLF=true;
79 int m=markpos;
80 markpos=-1;
81 return new String(buf,m,p-m-1,StandardCharsets.UTF_8);
82 }
83
84 if (b=='\n')
85 {
86 if (_skipLF)
87 {
88 _skipLF=false;
89 _seenCRLF=true;
90 markpos++;
91 continue;
92 }
93 int m=markpos;
94 markpos=-1;
95 return new String(buf,m,pos-m-1,StandardCharsets.UTF_8);
96 }
97 }
98 }
99
100 @Override
101 public synchronized int read() throws IOException
102 {
103 int b = super.read();
104 if (_skipLF)
105 {
106 _skipLF=false;
107 if (_seenCRLF && b=='\n')
108 b=super.read();
109 }
110 return b;
111 }
112
113 @Override
114 public synchronized int read(byte[] buf, int off, int len) throws IOException
115 {
116 if (_skipLF && len>0)
117 {
118 _skipLF=false;
119 if (_seenCRLF)
120 {
121 int b = super.read();
122 if (b==-1)
123 return -1;
124
125 if (b!='\n')
126 {
127 buf[off]=(byte)(0xff&b);
128 return 1+super.read(buf,off+1,len-1);
129 }
130 }
131 }
132
133 return super.read(buf,off,len);
134 }
135
136
137 }