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.util.HashMap;
18
19 import org.eclipse.jetty.http.AbstractGenerator;
20 import org.eclipse.jetty.http.HttpFields;
21 import org.eclipse.jetty.http.HttpGenerator;
22 import org.eclipse.jetty.http.HttpTokens;
23 import org.eclipse.jetty.http.HttpVersions;
24 import org.eclipse.jetty.io.Buffer;
25 import org.eclipse.jetty.io.Buffers;
26 import org.eclipse.jetty.io.ByteArrayBuffer;
27 import org.eclipse.jetty.io.EndPoint;
28 import org.eclipse.jetty.io.EofException;
29 import org.eclipse.jetty.util.TypeUtil;
30 import org.eclipse.jetty.util.log.Log;
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)
112 {
113 super(buffers, io);
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 flushBuffer();
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 flushBuffer();
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 public 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 flushBuffer();
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.getHeader();
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=HttpGenerator.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 int s=fields.size();
381 for (int f=0;f<s;f++)
382 {
383 HttpFields.Field field = fields.getField(f);
384 if (field==null)
385 continue;
386 num_fields++;
387
388 byte[] codes = (byte[]) __headerHash.get(field.getName());
389 if (codes != null)
390 {
391 _buffer.put(codes);
392 }
393 else
394 {
395 addString(field.getName());
396 }
397 addString(field.getValue());
398 }
399 }
400
401 if (!has_server && _status > 100 && getSendServerVersion())
402 {
403 num_fields++;
404 addString("Server");
405 addString(SERVER);
406 }
407
408
409
410
411 int tmp = _buffer.putIndex();
412 _buffer.setPutIndex(field_index);
413 addInt(num_fields);
414 _buffer.setPutIndex(tmp);
415
416
417
418
419 int payloadSize = _buffer.length() - 4;
420
421
422
423 addInt(2, payloadSize);
424 }
425 finally
426 {
427 _buffer = tmpbuf;
428 }
429
430
431 _state = STATE_CONTENT;
432
433 }
434
435
436
437
438
439
440
441 public void complete() throws IOException
442 {
443 if (_state == STATE_END)
444 return;
445
446 super.complete();
447
448 if (_state < STATE_FLUSHING)
449 {
450 _state = STATE_FLUSHING;
451 _needEOC = true;
452 }
453
454 flushBuffer();
455 }
456
457
458 public long flushBuffer() throws IOException
459 {
460 try
461 {
462 if (_state == STATE_HEADER && !_expectMore)
463 throw new IllegalStateException("State==HEADER");
464 prepareBuffers();
465
466 if (_endp == null)
467 {
468
469
470
471
472
473
474 if (!_expectMore && _needEOC && _buffer != null)
475 {
476 _buffer.put(AJP13_END_RESPONSE);
477 }
478 _needEOC = false;
479 return 0;
480 }
481
482
483
484 int total = 0;
485 long last_len = -1;
486 Flushing: while (true)
487 {
488 int len = -1;
489 int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
490
491
492 switch (to_flush)
493 {
494 case 7:
495 throw new IllegalStateException();
496
497
498 case 6:
499 len = _endp.flush(_header, _buffer, null);
500
501 break;
502 case 5:
503 throw new IllegalStateException();
504
505
506 case 4:
507 len = _endp.flush(_header);
508 break;
509 case 3:
510 throw new IllegalStateException();
511
512
513 case 2:
514 len = _endp.flush(_buffer);
515
516 break;
517 case 1:
518 throw new IllegalStateException();
519
520
521 case 0:
522 {
523
524 if (_header != null)
525 _header.clear();
526
527 _bufferPrepared = false;
528
529 if (_buffer != null)
530 {
531 _buffer.clear();
532
533
534
535 _buffer.setPutIndex(7);
536 _buffer.setGetIndex(7);
537
538
539
540
541
542 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
543 {
544
545 _buffer.put(_content);
546 _content.clear();
547 _content = null;
548 break Flushing;
549 }
550
551 }
552
553
554
555
556 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
557 {
558 if (_state == STATE_FLUSHING)
559 _state = STATE_END;
560
561
562
563
564
565
566
567 break Flushing;
568 }
569
570
571 prepareBuffers();
572 }
573 }
574
575
576
577 if (len <= 0)
578 {
579 if (last_len <= 0)
580 break Flushing;
581 break;
582 }
583 last_len = len;
584 total += len;
585 }
586
587
588
589 return total;
590 }
591 catch (IOException e)
592 {
593 Log.ignore(e);
594 throw (e instanceof EofException) ? e : new EofException(e);
595 }
596
597 }
598
599
600 private void prepareBuffers()
601 {
602 if (!_bufferPrepared)
603 {
604
605
606 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
607 {
608
609 int len = _buffer.put(_content);
610
611
612 if (len > 0 && _buffer.space() == 0)
613 {
614 len--;
615 _buffer.setPutIndex(_buffer.putIndex() - 1);
616 }
617 _content.skip(len);
618
619 if (_content.length() == 0)
620 _content = null;
621
622 if (_buffer.length() == 0)
623 {
624 _content = null;
625 }
626 }
627
628
629 if (_buffer != null)
630 {
631
632 int payloadSize = _buffer.length();
633
634
635
636
637
638
639 if (payloadSize > 0)
640 {
641 _bufferPrepared = true;
642
643 _buffer.put((byte) 0);
644 int put = _buffer.putIndex();
645 _buffer.setGetIndex(0);
646 _buffer.setPutIndex(0);
647 _buffer.put((byte) 'A');
648 _buffer.put((byte) 'B');
649 addInt(payloadSize + 4);
650 _buffer.put((byte) 3);
651 addInt(payloadSize);
652 _buffer.setPutIndex(put);
653 }
654 }
655
656 if (_needMore)
657 {
658
659 if (_header == null)
660 {
661 _header = _buffers.getHeader();
662 }
663
664 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
665 {
666 _header.put(AJP13_MORE_CONTENT);
667 _needMore = false;
668 }
669 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
670 {
671
672
673 _buffer.put(AJP13_MORE_CONTENT);
674 _needMore = false;
675 _bufferPrepared = true;
676 }
677
678 }
679
680 if (!_expectMore && _needEOC)
681 {
682 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
683 {
684
685 _header.put(AJP13_END_RESPONSE);
686 _needEOC = false;
687 }
688 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
689 {
690
691
692
693 _buffer.put(AJP13_END_RESPONSE);
694 _needEOC = false;
695 _bufferPrepared = true;
696 }
697 }
698 }
699 }
700
701
702 public boolean isComplete()
703 {
704 return !_expectMore && _state == STATE_END;
705 }
706
707
708 private void initContent() throws IOException
709 {
710 if (_buffer == null)
711 {
712 _buffer = _buffers.getBuffer();
713 _buffer.setPutIndex(7);
714 _buffer.setGetIndex(7);
715 }
716 }
717
718
719 private void addInt(int i)
720 {
721 _buffer.put((byte) ((i >> 8) & 0xFF));
722 _buffer.put((byte) (i & 0xFF));
723 }
724
725
726 private void addInt(int startIndex, int i)
727 {
728 _buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
729 _buffer.poke((startIndex + 1), (byte) (i & 0xFF));
730 }
731
732
733 private void addString(String str)
734 {
735 if (str == null)
736 {
737 addInt(0xFFFF);
738 return;
739 }
740
741
742
743 byte[] b = str.getBytes();
744
745 addInt(b.length);
746
747 _buffer.put(b);
748 _buffer.put((byte) 0);
749 }
750
751
752 private void addBuffer(Buffer b)
753 {
754 if (b == null)
755 {
756 addInt(0xFFFF);
757 return;
758 }
759
760 addInt(b.length());
761 _buffer.put(b);
762 _buffer.put((byte) 0);
763 }
764
765
766 public void getBodyChunk() throws IOException
767 {
768 _needMore = true;
769 _expectMore = true;
770 flushBuffer();
771 }
772
773
774 public void gotBody()
775 {
776 _needMore = false;
777 _expectMore = false;
778 }
779
780
781
782 public void sendCPong() throws IOException
783 {
784
785 Buffer buff = _buffers.getBuffer();
786 buff.put(AJP13_CPONG_RESPONSE);
787
788
789 do
790 {
791 _endp.flush(buff);
792 }
793 while(buff.length() >0);
794 _buffers.returnBuffer(buff);
795
796 reset(true);
797
798 }
799
800
801
802 }