1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.ajp;
15
16 import java.io.IOException;
17 import java.io.UnsupportedEncodingException;
18 import java.util.HashMap;
19
20 import org.eclipse.jetty.http.AbstractGenerator;
21 import org.eclipse.jetty.http.HttpFields;
22 import org.eclipse.jetty.http.HttpGenerator;
23 import org.eclipse.jetty.http.HttpTokens;
24 import org.eclipse.jetty.http.HttpVersions;
25 import org.eclipse.jetty.io.Buffer;
26 import org.eclipse.jetty.io.Buffers;
27 import org.eclipse.jetty.io.ByteArrayBuffer;
28 import org.eclipse.jetty.io.EndPoint;
29 import org.eclipse.jetty.io.EofException;
30 import org.eclipse.jetty.util.StringUtil;
31 import org.eclipse.jetty.util.TypeUtil;
32 import org.eclipse.jetty.util.log.Log;
33
34
35
36
37
38 public class Ajp13Generator extends AbstractGenerator
39 {
40 private static HashMap __headerHash = new HashMap();
41
42 static
43 {
44 byte[] xA001 =
45 { (byte) 0xA0, (byte) 0x01 };
46 byte[] xA002 =
47 { (byte) 0xA0, (byte) 0x02 };
48 byte[] xA003 =
49 { (byte) 0xA0, (byte) 0x03 };
50 byte[] xA004 =
51 { (byte) 0xA0, (byte) 0x04 };
52 byte[] xA005 =
53 { (byte) 0xA0, (byte) 0x05 };
54 byte[] xA006 =
55 { (byte) 0xA0, (byte) 0x06 };
56 byte[] xA007 =
57 { (byte) 0xA0, (byte) 0x07 };
58 byte[] xA008 =
59 { (byte) 0xA0, (byte) 0x08 };
60 byte[] xA009 =
61 { (byte) 0xA0, (byte) 0x09 };
62 byte[] xA00A =
63 { (byte) 0xA0, (byte) 0x0A };
64 byte[] xA00B =
65 { (byte) 0xA0, (byte) 0x0B };
66 __headerHash.put("Content-Type", xA001);
67 __headerHash.put("Content-Language", xA002);
68 __headerHash.put("Content-Length", xA003);
69 __headerHash.put("Date", xA004);
70 __headerHash.put("Last-Modified", xA005);
71 __headerHash.put("Location", xA006);
72 __headerHash.put("Set-Cookie", xA007);
73 __headerHash.put("Set-Cookie2", xA008);
74 __headerHash.put("Servlet-Engine", xA009);
75 __headerHash.put("Status", xA00A);
76 __headerHash.put("WWW-Authenticate", xA00B);
77
78 }
79
80
81
82
83 private static final byte[] AJP13_CPONG_RESPONSE =
84 { 'A', 'B', 0, 1, 9};
85
86 private static final byte[] AJP13_END_RESPONSE =
87 { 'A', 'B', 0, 2, 5, 1 };
88
89
90
91
92
93 private static final byte[] AJP13_MORE_CONTENT =
94 { 'A', 'B', 0, 3, 6, 31, -7 };
95
96 private static String SERVER = "Server: Jetty(6.0.x)";
97
98 public static void setServerVersion(String version)
99 {
100 SERVER = "Jetty(" + version + ")";
101 }
102
103
104 private boolean _expectMore = false;
105
106 private boolean _needMore = false;
107
108 private boolean _needEOC = false;
109
110 private boolean _bufferPrepared = false;
111
112
113 public Ajp13Generator(Buffers buffers, EndPoint io)
114 {
115 super(buffers, io);
116 }
117
118
119 @Override
120 public void reset(boolean returnBuffers)
121 {
122 super.reset(returnBuffers);
123
124 _needEOC = false;
125 _needMore = false;
126 _expectMore = false;
127 _bufferPrepared = false;
128 _last=false;
129
130
131
132 _state = STATE_HEADER;
133
134 _status = 0;
135 _version = HttpVersions.HTTP_1_1_ORDINAL;
136 _reason = null;
137 _method = null;
138 _uri = null;
139
140 _contentWritten = 0;
141 _contentLength = HttpTokens.UNKNOWN_CONTENT;
142 _last = false;
143 _head = false;
144 _noContent = false;
145 _close = false;
146
147
148
149
150 _header = null;
151 _buffer = null;
152 _content = null;
153
154
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 public void addContent(Buffer content, boolean last) throws IOException
173 {
174 if (_noContent)
175 {
176 content.clear();
177 return;
178 }
179
180 if (content.isImmutable())
181 throw new IllegalArgumentException("immutable");
182
183 if (_last || _state == STATE_END)
184 {
185 Log.debug("Ignoring extra content {}", content);
186 content.clear();
187 return;
188 }
189 _last = last;
190
191 if(!_endp.isOpen())
192 {
193 _state = STATE_END;
194 return;
195 }
196
197
198 if (_content != null && _content.length() > 0)
199 {
200
201 flushBuffer();
202 if (_content != null && _content.length() > 0)
203 throw new IllegalStateException("FULL");
204 }
205
206 _content = content;
207
208 _contentWritten += content.length();
209
210
211 if (_head)
212 {
213
214 content.clear();
215 _content = null;
216 }
217 else
218 {
219
220 initContent();
221
222 int len = 0;
223 len = _buffer.put(_content);
224
225
226 if (len > 0 && _buffer.space() == 0)
227 {
228 len--;
229 _buffer.setPutIndex(_buffer.putIndex() - 1);
230 }
231
232 _content.skip(len);
233
234 if (_content.length() == 0)
235 _content = null;
236 }
237 }
238
239
240
241
242
243
244
245
246
247
248 public boolean addContent(byte b) throws IOException
249 {
250
251 if (_noContent)
252 return false;
253
254 if (_last || _state == STATE_END)
255 throw new IllegalStateException("Closed");
256
257
258 if(!_endp.isOpen())
259 {
260 _state = STATE_END;
261 return false;
262 }
263
264
265 if (_content != null && _content.length() > 0)
266 {
267 flushBuffer();
268 if (_content != null && _content.length() > 0)
269 throw new IllegalStateException("FULL");
270 }
271
272 _contentWritten++;
273
274
275 if (_head)
276 return false;
277
278
279 initContent();
280
281
282
283 _buffer.put(b);
284
285 return _buffer.space() <= 1;
286 }
287
288
289
290
291
292
293
294
295
296 @Override
297 public int prepareUncheckedAddContent() throws IOException
298 {
299 if (_noContent)
300 return -1;
301
302 if (_last || _state == STATE_END)
303 throw new IllegalStateException("Closed");
304
305
306 if(!_endp.isOpen())
307 {
308 _state = STATE_END;
309 return -1;
310 }
311
312
313 Buffer content = _content;
314 if (content != null && content.length() > 0)
315 {
316 flushBuffer();
317 if (content != null && content.length() > 0)
318 throw new IllegalStateException("FULL");
319 }
320
321
322 initContent();
323
324 _contentWritten -= _buffer.length();
325
326
327 if (_head)
328 return Integer.MAX_VALUE;
329
330 return _buffer.space() - 1;
331 }
332
333
334 @Override
335 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
336 {
337 if (_state != STATE_HEADER)
338 return;
339
340 if (_last && !allContentAdded)
341 throw new IllegalStateException("last?");
342 _last = _last | allContentAdded;
343
344 boolean has_server = false;
345 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
346 _close = true;
347
348
349 if (_header == null)
350 _header = _buffers.getHeader();
351
352 Buffer tmpbuf = _buffer;
353 _buffer = _header;
354
355 try
356 {
357
358 _buffer.put((byte) 'A');
359 _buffer.put((byte) 'B');
360 addInt(0);
361 _buffer.put((byte) 0x4);
362 addInt(_status);
363 if (_reason == null)
364 _reason=HttpGenerator.getReasonBuffer(_status);
365 if (_reason == null)
366 _reason = new ByteArrayBuffer(TypeUtil.toString(_status));
367 addBuffer(_reason);
368
369 if (_status == 100 || _status == 204 || _status == 304)
370 {
371 _noContent = true;
372 _content = null;
373 }
374
375
376
377 int field_index = _buffer.putIndex();
378 addInt(0);
379
380 int num_fields = 0;
381
382 if (fields != null)
383 {
384
385 int s=fields.size();
386 for (int f=0;f<s;f++)
387 {
388 HttpFields.Field field = fields.getField(f);
389 if (field==null)
390 continue;
391 num_fields++;
392
393 byte[] codes = (byte[]) __headerHash.get(field.getName());
394 if (codes != null)
395 {
396 _buffer.put(codes);
397 }
398 else
399 {
400 addString(field.getName());
401 }
402 addString(field.getValue());
403 }
404 }
405
406 if (!has_server && _status > 100 && getSendServerVersion())
407 {
408 num_fields++;
409 addString("Server");
410 addString(SERVER);
411 }
412
413
414
415
416 int tmp = _buffer.putIndex();
417 _buffer.setPutIndex(field_index);
418 addInt(num_fields);
419 _buffer.setPutIndex(tmp);
420
421
422
423
424 int payloadSize = _buffer.length() - 4;
425
426
427
428 addInt(2, payloadSize);
429 }
430 finally
431 {
432 _buffer = tmpbuf;
433 }
434
435
436 _state = STATE_CONTENT;
437
438 }
439
440
441
442
443
444
445
446 @Override
447 public void complete() throws IOException
448 {
449 if (_state == STATE_END)
450 return;
451
452 super.complete();
453
454 if (_state < STATE_FLUSHING)
455 {
456 _state = STATE_FLUSHING;
457 _needEOC = true;
458 }
459
460 flushBuffer();
461 }
462
463
464 @Override
465 public long flushBuffer() throws IOException
466 {
467 try
468 {
469 if (_state == STATE_HEADER && !_expectMore)
470 throw new IllegalStateException("State==HEADER");
471 prepareBuffers();
472
473 if (_endp == null)
474 {
475
476
477
478
479
480
481 if (!_expectMore && _needEOC && _buffer != null)
482 {
483 _buffer.put(AJP13_END_RESPONSE);
484 }
485 _needEOC = false;
486 return 0;
487 }
488
489
490
491 int total = 0;
492 long last_len = -1;
493 Flushing: while (true)
494 {
495 int len = -1;
496 int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
497
498
499 switch (to_flush)
500 {
501 case 7:
502 throw new IllegalStateException();
503
504
505 case 6:
506 len = _endp.flush(_header, _buffer, null);
507
508 break;
509 case 5:
510 throw new IllegalStateException();
511
512
513 case 4:
514 len = _endp.flush(_header);
515 break;
516 case 3:
517 throw new IllegalStateException();
518
519
520 case 2:
521 len = _endp.flush(_buffer);
522
523 break;
524 case 1:
525 throw new IllegalStateException();
526
527
528 case 0:
529 {
530
531 if (_header != null)
532 _header.clear();
533
534 _bufferPrepared = false;
535
536 if (_buffer != null)
537 {
538 _buffer.clear();
539
540
541
542 _buffer.setPutIndex(7);
543 _buffer.setGetIndex(7);
544
545
546
547
548
549 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
550 {
551
552 _buffer.put(_content);
553 _content.clear();
554 _content = null;
555 break Flushing;
556 }
557
558 }
559
560
561
562
563 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
564 {
565 if (_state == STATE_FLUSHING)
566 _state = STATE_END;
567
568
569
570
571
572
573
574 break Flushing;
575 }
576
577
578 prepareBuffers();
579 }
580 }
581
582
583
584 if (len <= 0)
585 {
586 if (last_len <= 0)
587 break Flushing;
588 break;
589 }
590 last_len = len;
591 total += len;
592 }
593
594
595
596 return total;
597 }
598 catch (IOException e)
599 {
600 Log.ignore(e);
601 throw (e instanceof EofException) ? e : new EofException(e);
602 }
603
604 }
605
606
607 private void prepareBuffers()
608 {
609 if (!_bufferPrepared)
610 {
611
612
613 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
614 {
615
616 int len = _buffer.put(_content);
617
618
619 if (len > 0 && _buffer.space() == 0)
620 {
621 len--;
622 _buffer.setPutIndex(_buffer.putIndex() - 1);
623 }
624 _content.skip(len);
625
626 if (_content.length() == 0)
627 _content = null;
628
629 if (_buffer.length() == 0)
630 {
631 _content = null;
632 }
633 }
634
635
636 if (_buffer != null)
637 {
638
639 int payloadSize = _buffer.length();
640
641
642
643
644
645
646 if (payloadSize > 0)
647 {
648 _bufferPrepared = true;
649
650 _buffer.put((byte) 0);
651 int put = _buffer.putIndex();
652 _buffer.setGetIndex(0);
653 _buffer.setPutIndex(0);
654 _buffer.put((byte) 'A');
655 _buffer.put((byte) 'B');
656 addInt(payloadSize + 4);
657 _buffer.put((byte) 3);
658 addInt(payloadSize);
659 _buffer.setPutIndex(put);
660 }
661 }
662
663 if (_needMore)
664 {
665
666 if (_header == null)
667 {
668 _header = _buffers.getHeader();
669 }
670
671 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
672 {
673 _header.put(AJP13_MORE_CONTENT);
674 _needMore = false;
675 }
676 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
677 {
678
679
680 _buffer.put(AJP13_MORE_CONTENT);
681 _needMore = false;
682 _bufferPrepared = true;
683 }
684
685 }
686
687 if (!_expectMore && _needEOC)
688 {
689 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
690 {
691
692 _header.put(AJP13_END_RESPONSE);
693 _needEOC = false;
694 }
695 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
696 {
697
698
699
700 _buffer.put(AJP13_END_RESPONSE);
701 _needEOC = false;
702 _bufferPrepared = true;
703 }
704 }
705 }
706 }
707
708
709 @Override
710 public boolean isComplete()
711 {
712 return !_expectMore && _state == STATE_END;
713 }
714
715
716 private void initContent() throws IOException
717 {
718 if (_buffer == null)
719 {
720 _buffer = _buffers.getBuffer();
721 _buffer.setPutIndex(7);
722 _buffer.setGetIndex(7);
723 }
724 }
725
726
727 private void addInt(int i)
728 {
729 _buffer.put((byte) ((i >> 8) & 0xFF));
730 _buffer.put((byte) (i & 0xFF));
731 }
732
733
734 private void addInt(int startIndex, int i)
735 {
736 _buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
737 _buffer.poke((startIndex + 1), (byte) (i & 0xFF));
738 }
739
740
741 private void addString(String str) throws UnsupportedEncodingException
742 {
743 if (str == null)
744 {
745 addInt(0xFFFF);
746 return;
747 }
748
749
750
751 byte[] b = str.getBytes(StringUtil.__ISO_8859_1);
752
753 addInt(b.length);
754
755 _buffer.put(b);
756 _buffer.put((byte) 0);
757 }
758
759
760 private void addBuffer(Buffer b)
761 {
762 if (b == null)
763 {
764 addInt(0xFFFF);
765 return;
766 }
767
768 addInt(b.length());
769 _buffer.put(b);
770 _buffer.put((byte) 0);
771 }
772
773
774 public void getBodyChunk() throws IOException
775 {
776 _needMore = true;
777 _expectMore = true;
778 flushBuffer();
779 }
780
781
782 public void gotBody()
783 {
784 _needMore = false;
785 _expectMore = false;
786 }
787
788
789
790 public void sendCPong() throws IOException
791 {
792
793 Buffer buff = _buffers.getBuffer();
794 buff.put(AJP13_CPONG_RESPONSE);
795
796
797 do
798 {
799 _endp.flush(buff);
800 }
801 while(buff.length() >0);
802 _buffers.returnBuffer(buff);
803
804 reset(true);
805
806 }
807
808
809
810 }