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