Ticket #4568: pb.xhtml.patch
| File pb.xhtml.patch, 97.8 KB (added by jdb, 3 years ago) |
|---|
-
doc/core/howto/pb-clients.xhtml
diff --git a/doc/core/howto/pb-clients.xhtml b/doc/core/howto/pb-clients.xhtml index e6ecf86..89d2c8c 100644
a b 15 15 16 16 <p>In more complicated cases, for example an <code>Avatar</code> that 17 17 represents a player object which is persistent in the game universe, 18 we will want connections from the same player to use the same19 <code>Avatar</code>.</p>20 21 <p>Another thing which is necessary in more complicated scenarios 22 is notifying a player asynchronously. While it is possible, of 23 course, to allow a player to call 24 <code>perspective_remoteListener(referencable)</code> that would25 mean both duplication of code and a higher latency in logging in, 26 b oth bad.</p>18 we will want connections from the same player to use the 19 same <code>Avatar</code>.</p> 20 21 <p>Another thing which is necessary in more complicated scenarios is 22 notifying a player asynchronously. While it is possible, of course, to 23 allow a player to 24 call <code>perspective_remoteListener(referencable)</code> that would 25 mean both duplication of code and a higher latency in logging in, both 26 bad.</p> 27 27 28 28 <p>In previous sections all realms looked to be identical. 29 29 In this one we will show the usefulness of realms in accomplishing -
doc/core/howto/pb-copyable.xhtml
diff --git a/doc/core/howto/pb-copyable.xhtml b/doc/core/howto/pb-copyable.xhtml index 42d1bf3..f4acffb 100644
a b 69 69 other data structures when executed. Once previously-trusted data is 70 70 subverted, the rest of the program is compromised.</p> 71 71 72 <p>The built-in Python <q>batteries included</q> classes are relatively73 tame, but you still wouldn't want to let a foreign program use them to 74 create arbitrary objects in your namespace or on your computer. Imagine a 75 protocol that involved sending a file-like object with a <code>read()</code> 76 method that was supposed to used later to retrieve a document. Then imagine 77 what if that object were created with 78 <code>os.fdopen("~/.gnupg/secring.gpg")</code>. Or an instance of 79 <code>telnetlib.Telnet("localhost", "chargen")</code>. </p>80 81 <p>Classes you've written for your own program are likely to have far more82 power. They may run code during <code>__init__</code>, or even have special 83 meaning simply because of their existence. A program might have 84 <code>User</code> objects to represent user accounts, and have a rule that 85 says all <code>User</code> objects in the system are referenced when 86 authorizing a login session. (In this system, <code>User.__init__</code> 87 would probably add the object to a global list of known users). The simple 88 act of creating an object would give access to somebody. If you could be 89 tricked into creating a bad object, an unauthorized user would get 90 access.</p>72 <p>The built-in Python <q>batteries included</q> classes are 73 relatively tame, but you still wouldn't want to let a foreign program 74 use them to create arbitrary objects in your namespace or on your 75 computer. Imagine a protocol that involved sending a file-like object 76 with a <code>read()</code> method that was supposed to used later to 77 retrieve a document. Then imagine what if that object were created 78 with <code>os.fdopen("~/.gnupg/secring.gpg")</code>. Or an instance 79 of <code>telnetlib.Telnet("localhost", "chargen")</code>. </p> 80 81 <p>Classes you've written for your own program are likely to have far 82 more power. They may run code during <code>__init__</code>, or even 83 have special meaning simply because of their existence. A program 84 might have <code>User</code> objects to represent user accounts, and 85 have a rule that says all <code>User</code> objects in the system are 86 referenced when authorizing a login session. (In this 87 system, <code>User.__init__</code> would probably add the object to a 88 global list of known users). The simple act of creating an object 89 would give access to somebody. If you could be tricked into creating a 90 bad object, an unauthorized user would get access.</p> 91 91 92 92 <p>So object creation needs to be part of a system's security design. The 93 93 dotted line between <q>trusted inside</q> and <q>untrusted outside</q> needs … … 117 117 with the <code class="API" 118 118 base="twisted.spread.jelly">setUnjellyableForClass</code> function<!-- 119 119 120 --><span class="footnote"> <p>Note that, in this context, <q>unjelly</q> is 121 a verb with the opposite meaning of <q>jelly</q>. The verb <q>to jelly</q> 122 means to serialize an object or data structure into a sequence of bytes (or 123 other primitive transmittable/storable representation), while <q>to 124 unjelly</q> means to unserialize the bytestream into a live object in the 125 receiver's memory space. <q>Unjellyable</q> is a noun, (<em>not</em> an 120 --><span class="footnote"> <p>Note that, in this 121 context, <q>unjelly</q> is a verb with the opposite meaning 122 of <q>jelly</q>. The verb <q>to jelly</q> means to serialize an object 123 or data structure into a sequence of bytes (or other primitive 124 transmittable/storable representation), while <q>to unjelly</q> means 125 to unserialize the bytestream into a live object in the receiver's 126 memory space. <q>Unjellyable</q> is a noun, (<em>not</em> an 126 127 adjective), referring to the the class that serves as a destination or 127 recipient of the unjellying process. <q>A is unjellyable into B</q> means128 that a serialized representation A (of some remote object) can be 129 unserialized into a local object of type B. It is these objects <q>B</q> 130 that are the <q>Unjellyable</q> second argument of the 131 <code>setUnjellyableForClass</code> function.</p>128 recipient of the unjellying process. <q>A is unjellyable into B</q> 129 means that a serialized representation A (of some remote object) can 130 be unserialized into a local object of type B. It is these 131 objects <q>B</q> that are the <q>Unjellyable</q> second argument of 132 the <code>setUnjellyableForClass</code> function.</p> 132 133 133 134 <p>In particular, <q>unjellyable</q> does <em>not</em> mean <q>cannot be 134 135 jellied</q>. <code class="API" … … 139 140 140 141 141 142 This function takes a remote/sender class reference (either the 142 fully-qualified name as used by the sending end, or a class object from143 which the name can be extracted), and a local/recipient class (used to 144 create the local representation for incoming serialized objects). Whenever 145 the remote end sends an object, the class name that they transmit is looked 146 up in the table controlled by this function. If a matching class is found, 147 it is used to create the local object. If not, you get the 148 <code>InsecureJelly</code> exception.</p>149 150 <p>In general you expect both ends to share the same codebase: either you151 control the program that is running on both ends of the wire, or both 152 programs share some kind of common language that is implemented in code 153 which exists on both ends. You wouldn't expect them to send you an object of 154 the MyFooziWhatZit class unless you also had a definition for that class. So 155 it is reasonable for the Jelly layer to reject all incoming classes except 156 the ones that you have explicitly marked with 157 <code>setUnjellyableForClass</code>. But keep in mind that the sender's idea 158 of a <code>User</code> object might differ from the recipient's, either 159 through namespace collisions between unrelated packages, version skew 160 between nodes that haven't been updated at the same rate, or a malicious 161 intruder trying to cause your code to fail in some interesting or 162 potentially vulnerable way.</p>143 fully-qualified name as used by the sending end, or a class object 144 from which the name can be extracted), and a local/recipient class 145 (used to create the local representation for incoming serialized 146 objects). Whenever the remote end sends an object, the class name that 147 they transmit is looked up in the table controlled by this 148 function. If a matching class is found, it is used to create the local 149 object. If not, you get the <code>InsecureJelly</code> exception.</p> 150 151 <p>In general you expect both ends to share the same codebase: either 152 you control the program that is running on both ends of the wire, or 153 both programs share some kind of common language that is implemented 154 in code which exists on both ends. You wouldn't expect them to send 155 you an object of the MyFooziWhatZit class unless you also had a 156 definition for that class. So it is reasonable for the Jelly layer to 157 reject all incoming classes except the ones that you have explicitly 158 marked with <code>setUnjellyableForClass</code>. But keep in mind that 159 the sender's idea of a <code>User</code> object might differ from the 160 recipient's, either through namespace collisions between unrelated 161 packages, version skew between nodes that haven't been updated at the 162 same rate, or a malicious intruder trying to cause your code to fail 163 in some interesting or potentially vulnerable way.</p> 163 164 164 165 165 166 <h2>pb.Copyable</h2> … … 170 171 <a href="listings/pb/copy_sender.py" class="py-listing">copy_sender.py</a> 171 172 <a href="listings/pb/copy_receiver.tac" class="py-listing">copy_receiver.tac</a> 172 173 173 <p>The sending side has a class called <code>LilyPond</code>. To make this 174 eligble for transport through <code>callRemote</code> (either as an 175 argument, a return value, or something referenced by either of those [like a 176 dictionary value]), it must inherit from one of the four <code class="API" 177 base="twisted.spread.pb">Serializable</code> classes. In this section, 178 we focus on <code class="API" base="twisted.spread.pb">Copyable</code>. 179 The copyable subclass of <code>LilyPond</code> is called 180 <code>CopyPond</code>. We create an instance of it and send it through 181 <code>callRemote</code> as an argument to the receiver's 182 <code>remote_takePond</code> method. The Jelly layer will serialize 183 (<q>jelly</q>) that object as an instance with a class name of 174 <p>The sending side has a class called <code>LilyPond</code>. To make 175 this eligble for transport through <code>callRemote</code> (either as 176 an argument, a return value, or something referenced by either of 177 those [like a dictionary value]), it must inherit from one of the 178 four <code class="API" base="twisted.spread.pb">Serializable</code> 179 classes. In this section, we focus on <code class="API" 180 base="twisted.spread.pb">Copyable</code>. The copyable subclass 181 of <code>LilyPond</code> is called <code>CopyPond</code>. We create an 182 instance of it and send it through <code>callRemote</code> as an 183 argument to the receiver's <code>remote_takePond</code> method. The 184 Jelly layer will serialize (<q>jelly</q>) that object as an instance 185 with a class name of 184 186 <q>copy_sender.CopyPond</q> and some chunk of data that represents the 185 object's state. <code>pond.__class__.__module__</code> and 186 <code>pond.__class__.__name__</code> are used to derive the class name 187 string. The object's <code class="API" 188 base="twisted.spread.pb.Copyable">getStateToCopy</code> method is 189 used to get the state: this is provided by <code class="API" 190 base="twisted.spread">pb.Copyable</code>, and the default just retrieves 191 <code>self.__dict__</code>. This works just like the optional 192 <code>__getstate__</code> method used by <code>pickle</code>. The pair of 193 name and state are sent over the wire to the receiver.</p> 194 195 <p>The receiving end defines a local class named <code>ReceiverPond</code> 196 to represent incoming <code>LilyPond</code> instances. This class derives 197 from the sender's <code>LilyPond</code> class (with a fully-qualified name 198 of <code>copy_sender.LilyPond</code>), which specifies how we expect it to 199 behave. We trust that this is the same <code>LilyPond</code> class as the 200 sender used. (At the very least, we hope ours will be able to accept a state 201 created by theirs). It also inherits from <code class="API" 202 base="twisted.spread">pb.RemoteCopy</code>, which is a requirement for all 203 classes that act in this local-representative role (those which are given to 204 the second argument of <code>setUnjellyableForClass</code>). 205 <code>RemoteCopy</code> provides the methods that tell the Jelly layer how 206 to create the local object from the incoming serialized state.</p> 187 object's state. <code>pond.__class__.__module__</code> 188 and <code>pond.__class__.__name__</code> are used to derive the class 189 name string. The object's <code class="API" 190 base="twisted.spread.pb.Copyable">getStateToCopy</code> method is used 191 to get the state: this is provided by <code class="API" 192 base="twisted.spread">pb.Copyable</code>, and the default just 193 retrieves <code>self.__dict__</code>. This works just like the 194 optional <code>__getstate__</code> method used 195 by <code>pickle</code>. The pair of name and state are sent over the 196 wire to the receiver.</p> 197 198 <p>The receiving end defines a local class 199 named <code>ReceiverPond</code> to represent 200 incoming <code>LilyPond</code> instances. This class derives from the 201 sender's <code>LilyPond</code> class (with a fully-qualified name 202 of <code>copy_sender.LilyPond</code>), which specifies how we expect 203 it to behave. We trust that this is the same <code>LilyPond</code> 204 class as the sender used. (At the very least, we hope ours will be 205 able to accept a state created by theirs). It also inherits 206 from <code class="API" base="twisted.spread">pb.RemoteCopy</code>, 207 which is a requirement for all classes that act in this 208 local-representative role (those which are given to the second 209 argument 210 of <code>setUnjellyableForClass</code>). <code>RemoteCopy</code> 211 provides the methods that tell the Jelly layer how to create the local 212 object from the incoming serialized state.</p> 207 213 208 214 <p>Then <code>setUnjellyableForClass</code> is used to register the two 209 215 classes. This has two effects: instances of the remote class (the first … … 211 217 the local class (the second argument) will be used to contain the state that 212 218 is transmitted when the sender serializes the remote object.</p> 213 219 214 <p>When the receiver unserializes (<q>unjellies</q>) the object, it will215 create an instance of the local <code>ReceiverPond</code> class, and hand 216 the transmitted state (usually in the form of a dictionary) to that object's 217 <code class="API"220 <p>When the receiver unserializes (<q>unjellies</q>) the object, it 221 will create an instance of the local <code>ReceiverPond</code> class, 222 and hand the transmitted state (usually in the form of a dictionary) 223 to that object's <code class="API" 218 224 base="twisted.spread.pb.RemoteCopy">setCopyableState</code> method. 219 This acts just like the <code>__setstate__</code> method that220 <code>pickle</code> uses when unserializing an object. 221 <code>getStateToCopy</code>/<code>setCopyableState</code> are distinct from 222 <code>__getstate__</code>/<code>__setstate__</code> to allow objects to be 223 persisted (across time) differently than they are transmitted (across 224 [memory]space).</p>225 This acts just like the <code>__setstate__</code> method 226 that <code>pickle</code> uses when unserializing an 227 object. <code>getStateToCopy</code>/<code>setCopyableState</code> are 228 distinct from <code>__getstate__</code>/<code>__setstate__</code> to 229 allow objects to be persisted (across time) differently than they are 230 transmitted (across [memory]space).</p> 225 231 226 232 <p>When this is run, it produces the following output:</p> 227 233 … … 247 253 248 254 <h3>Controlling the Copied State</h3> 249 255 250 <p>By overriding <code>getStateToCopy</code> and 251 <code>setCopyableState</code>, you can control how the object is transmitted 252 over the wire. For example, you might want perform some data-reduction: 253 pre-compute some results instead of sending all the raw data over the wire. 254 Or you could replace references to a local object on the sender's side with 255 markers before sending, then upon receipt replace those markers with 256 references to a receiver-side proxy that could perform the same operations 257 against a local cache of data.</p> 256 <p>By overriding <code>getStateToCopy</code> 257 and <code>setCopyableState</code>, you can control how the object is 258 transmitted over the wire. For example, you might want perform some 259 data-reduction: pre-compute some results instead of sending all the 260 raw data over the wire. Or you could replace references to a local 261 object on the sender's side with markers before sending, then upon 262 receipt replace those markers with references to a receiver-side proxy 263 that could perform the same operations against a local cache of 264 data.</p> 258 265 259 266 <p>Another good use for <code>getStateToCopy</code> is to implement 260 <q>local-only</q> attributes: data that is only accessible by the local261 process, not to any remote users. For example, a <code>.password</code> 262 a ttribute could be removed from the object state before sending to a remote263 s ystem. Combined with the fact that <code>Copyable</code> objects return264 unchanged from a round trip, this could be used to build a 265 challenge-response system (in fact PB does this with 266 <code>pb.Referenceable</code> objects to implement authorization as 267 described <a href="pb-cred.xhtml">here</a>).</p>267 <q>local-only</q> attributes: data that is only accessible by the 268 local process, not to any remote users. For example, 269 a <code>.password</code> attribute could be removed from the object 270 state before sending to a remote system. Combined with the fact 271 that <code>Copyable</code> objects return unchanged from a round trip, 272 this could be used to build a challenge-response system (in fact PB 273 does this with <code>pb.Referenceable</code> objects to implement 274 authorization as described <a href="pb-cred.xhtml">here</a>).</p> 268 275 269 276 <p>Whatever <code>getStateToCopy</code> returns from the sending object will 270 277 be serialized and sent over the wire; <code>setCopyableState</code> gets … … 276 283 <a href="listings/pb/copy2_sender.py" class="py-listing">copy2_sender.py</a> 277 284 <a href="listings/pb/copy2_receiver.py" class="py-listing">copy2_receiver.py</a> 278 285 279 <p>In this example, the classes are defined in a separate source file, which 280 also sets up the binding between them. The <code>SenderPond</code> and 281 <code>ReceiverPond</code> are unrelated save for this binding: they happen 282 to implement the same methods, but use different internal instance variables 283 to accomplish them.</p> 286 <p>In this example, the classes are defined in a separate source file, 287 which also sets up the binding between 288 them. The <code>SenderPond</code> and <code>ReceiverPond</code> are 289 unrelated save for this binding: they happen to implement the same 290 methods, but use different internal instance variables to accomplish 291 them.</p> 284 292 285 293 <p>The recipient of the object doesn't even have to import the class 286 294 definition into their namespace. It is sufficient that they import the class … … 426 434 427 435 --><span class="footnote"> this is actually a <code class="API" 428 436 base="twisted.spread.pb">RemoteCacheObserver</code>, but it isn't very 429 useful to subclass or modify, so simply treat it as a little demon that sits430 in your <code>pb.Cacheable</code> class and helps you distribute change 431 notifications. The only useful thing to do with it is to run its 432 <code>callRemote</code> method, which acts just like a normal 433 <code>pb.Referenceable</code>'s method of the same name.</span>437 useful to subclass or modify, so simply treat it as a little demon 438 that sits in your <code>pb.Cacheable</code> class and helps you 439 distribute change notifications. The only useful thing to do with it 440 is to run its <code>callRemote</code> method, which acts just like a 441 normal <code>pb.Referenceable</code>'s method of the same name.</span> 434 442 435 443 that points at that receiver-side cache. Every time the state of the object 436 444 is changed, you give a message to the observer, informing them of the 437 445 change. The other method, <code>stoppedObserving</code>, is called when the 438 446 remote cache goes away, so that you can stop sending updates.</p> 439 447 440 <p>On the receiver end, you make your cache class inherit from <code 441 class="API" base="twisted.spread">pb.RemoteCache</code>, and implement the 442 <code>setCopyableState</code> as you would for a <code>pb.RemoteCopy</code> 443 object. In addition, you must implement methods to receive the updates sent 444 to the observer by the <code>pb.Cacheable</code>: these methods should have 445 names that start with <code>observe_</code>, and match the 446 <code>callRemote</code> invocations from the sender side just as the usual 447 <code>remote_*</code> and <code>perspective_*</code> methods match normal 448 <code>callRemote</code> calls. </p> 448 <p>On the receiver end, you make your cache class inherit 449 from <code class="API" base="twisted.spread">pb.RemoteCache</code>, 450 and implement the <code>setCopyableState</code> as you would for 451 a <code>pb.RemoteCopy</code> object. In addition, you must implement 452 methods to receive the updates sent to the observer by 453 the <code>pb.Cacheable</code>: these methods should have names that 454 start with <code>observe_</code>, and match 455 the <code>callRemote</code> invocations from the sender side just as 456 the usual <code>remote_*</code> and <code>perspective_*</code> methods 457 match normal <code>callRemote</code> calls. </p> 449 458 450 459 <p>The first time a reference to the <code>pb.Cacheable</code> object is 451 460 sent to any particular recipient, a sender-side Observer will be created for … … 455 464 using <code>setCopyableState</code> just like <code>pb.RemoteCopy</code>, 456 465 described above (in fact it inherits from that class). </p> 457 466 458 <p>After that, your <q>setter</q> functions on the sender side should call459 <code>callRemote</code> on the Observer, which causes <code>observe_*</code> 460 methods to run on the receiver, which are then supposed to update the 461 receiver-local (cached) state.</p>467 <p>After that, your <q>setter</q> functions on the sender side should 468 call <code>callRemote</code> on the Observer, which 469 causes <code>observe_*</code> methods to run on the receiver, which 470 are then supposed to update the receiver-local (cached) state.</p> 462 471 463 472 <p>When the receiver stops following the cached object and the last 464 473 reference goes away, the <code>pb.RemoteCache</code> object can be freed. … … 471 480 away.</p> 472 481 473 482 <p>With the <code>pb.Cacheable</code> and <code>pb.RemoteCache</code> 474 classes in place, bound together by a call to 475 <code>pb.setUnjellyableForClass</code>, all that remains is to pass a 476 reference to your <code>pb.Cacheable</code> over the wire to the remote end. 477 The corresponding <code>pb.RemoteCache</code> object will automatically be 478 created, and the matching methods will be used to keep the receiver-side 479 slave object in sync with the sender-side master object.</p> 483 classes in place, bound together by a call 484 to <code>pb.setUnjellyableForClass</code>, all that remains is to pass 485 a reference to your <code>pb.Cacheable</code> over the wire to the 486 remote end. The corresponding <code>pb.RemoteCache</code> object will 487 automatically be created, and the matching methods will be used to 488 keep the receiver-side slave object in sync with the sender-side 489 master object.</p> 480 490 481 491 <h3>Example</h3> 482 492 … … 571 581 in <code class="API">twisted.spread.flavors</code>, 572 582 where <code>pb.Cacheable</code> is implemented.</li> 573 583 574 <li><code class="API">twisted.manhole.explorer</code> uses 575 <code>Cacheable</code>, and does some fairly interesting things with it.</li> 584 <li><code class="API">twisted.manhole.explorer</code> 585 uses <code>Cacheable</code>, and does some fairly interesting things 586 with it.</li> 576 587 <!-- (XXX: I've heard explorer is currently broken, it might not be a good --> 577 588 <!-- example to recommend)</li> --> 578 589 -
doc/core/howto/pb-cred.xhtml
diff --git a/doc/core/howto/pb-cred.xhtml b/doc/core/howto/pb-cred.xhtml index ac6ba05..11c0eee 100644
a b 32 32 33 33 <h2>Compartmentalizing Services</h2> 34 34 35 <p>Imagine how you would write a chat server using PB. The first step might 36 be a <code>ChatServer</code> object which had a bunch of 37 <code>pb.RemoteReference</code>s that point at user clients. Pretend that 38 those clients offered a <code>remote_print</code> method which lets the 39 server print a message on the user's console. In that case, the server might 40 look something like this:</p> 35 <p>Imagine how you would write a chat server using PB. The first step 36 might be a <code>ChatServer</code> object which had a bunch 37 of <code>pb.RemoteReference</code>s that point at user 38 clients. Pretend that those clients offered 39 a <code>remote_print</code> method which lets the server print a 40 message on the user's console. In that case, the server might look 41 something like this:</p> 41 42 42 43 <pre class="python"> 43 44 class ChatServer(pb.Referenceable): … … 59 60 message)) 60 61 </pre> 61 62 62 <p>For now, assume that all clients have somehow acquired a 63 <code>pb.RemoteReference</code> to this <code>ChatServer</code> object, 64 perhaps using <code>pb.Root</code> and <code>getRootObject</code> as 65 described in the <a href="pb-usage.xhtml">previous chapter</a>. In this 66 scheme, when a user sends a message to the group, their client runs 67 something like the following:</p> 63 <p>For now, assume that all clients have somehow acquired 64 a <code>pb.RemoteReference</code> to this <code>ChatServer</code> 65 object, perhaps using <code>pb.Root</code> 66 and <code>getRootObject</code> as described in 67 the <a href="pb-usage.xhtml">previous chapter</a>. In this scheme, 68 when a user sends a message to the group, their client runs something 69 like the following:</p> 68 70 69 71 <pre class="python"> 70 72 remotegroup.callRemote("sendMessage", "alice", "Hi, my name is alice.") … … 94 96 <p>(In general, learn to get suspicious if you see any argument of a 95 97 remotely-invokable method described as <q>must be X</q>)</p> 96 98 97 <p>The best way to fix this is to keep track of the user's name locally,98 rather than asking them to send it to the server with each message. The best 99 place to keep state is in an object, so this suggests we need a per-user 100 object. Rather than choosing an obvious name<span class="footnote">the 101 obvious name is clearly 102 <code>ServerSidePerUserObjectWhichNobodyElseHasAccessTo</code>, but because 103 python makes everything else so easy to read, it only seems fair to make 104 your audience work for <em>something</em></span>, let's call this the 105 <code>User</code> class.99 <p>The best way to fix this is to keep track of the user's name 100 locally, rather than asking them to send it to the server with each 101 message. The best place to keep state is in an object, so this 102 suggests we need a per-user object. Rather than choosing an obvious 103 name<span class="footnote">the obvious name is 104 clearly <code>ServerSidePerUserObjectWhichNobodyElseHasAccessTo</code>, 105 but because python makes everything else so easy to read, it only 106 seems fair to make your audience work for <em>something</em></span>, 107 let's call this the <code>User</code> class. 106 108 </p> 107 109 108 110 <pre class="python"> … … 133 135 user.send("<%s> says: %s" % (from_username, message)) 134 136 </pre> 135 137 136 <p>Again, assume that each remote client gets access to a single 137 <code>User</code> object, which is created with the proper username.</p> 138 <p>Again, assume that each remote client gets access to a 139 single <code>User</code> object, which is created with the proper 140 username.</p> 138 141 139 142 <p>Note how the <code>ChatServer</code> object has no remote access: it 140 143 isn't even <code>pb.Referenceable</code> anymore. This means that all access 141 144 to it must be mediated through other objects, with code that is under your 142 145 control.</p> 143 146 144 <p>As long as Alice only has access to her own <code>User</code> object, she 145 can no longer spoof Bob. The only way for her to invoke 146 <code>ChatServer.sendMessage</code> is to call her <code>User</code> 147 object's <code>remote_sendMessage</code> method, and that method uses its 148 own state to provide the <code>from_username</code> argument. It doesn't 149 give her any way to change that state.</p> 150 151 <p>This restriction is important. The <code>User</code> object is able to 152 maintain its own integrity because there is a wall between the object and 153 the client: the client cannot inspect or modify internal state, like the 154 <code>.name</code> attribute. The only way through this wall is via remote 155 method invocations, and the only control Alice has over those invocations is 156 when they get invoked and what arguments they are given.</p> 147 <p>As long as Alice only has access to her own <code>User</code> 148 object, she can no longer spoof Bob. The only way for her to 149 invoke <code>ChatServer.sendMessage</code> is to call 150 her <code>User</code> object's <code>remote_sendMessage</code> method, 151 and that method uses its own state to provide 152 the <code>from_username</code> argument. It doesn't give her any way 153 to change that state.</p> 154 155 <p>This restriction is important. The <code>User</code> object is able 156 to maintain its own integrity because there is a wall between the 157 object and the client: the client cannot inspect or modify internal 158 state, like the <code>.name</code> attribute. The only way through 159 this wall is via remote method invocations, and the only control Alice 160 has over those invocations is when they get invoked and what arguments 161 they are given.</p> 157 162 158 163 <div class="note"> 159 164 <p>No object can maintain its integrity against local threats: by design, … … 165 170 166 171 <h3>Unforgeable References</h3> 167 172 168 <p>Now suppose you wanted to implement group parameters, for example a mode169 in which nobody was allowed to talk about mattresses because some users were170 sensitive and calming them down after someone said <q>mattress</q> is a 171 hassle that were best avoided altogether. Again, per-group state implies a 172 per-group object. We'll go out on a limb and call this the 173 <code>Group</code> object:</p>173 <p>Now suppose you wanted to implement group parameters, for example a 174 mode in which nobody was allowed to talk about mattresses because some 175 users were sensitive and calming them down after someone 176 said <q>mattress</q> is a hassle that were best avoided 177 altogether. Again, per-group state implies a per-group object. We'll 178 go out on a limb and call this the <code>Group</code> object:</p> 174 179 175 180 <pre class="python"> 176 181 class User(pb.Referenceable): … … 207 212 </pre> 208 213 209 214 210 <p>This example takes advantage of the fact that211 <code>pb.Referenceable</code> objects sent over a wire can be returned to 212 you, and they will be turned into references to the same object that you 213 o riginally sent. The client cannot modify the object in any way: all they214 can do is point at it and invoke its <code>remote_*</code> methods. Thus, 215 you can be sure that the <code>.name</code> attribute remains the same as 216 you left it. In this case, the client code would look something like 217 this :</p>215 <p>This example takes advantage of the fact 216 that <code>pb.Referenceable</code> objects sent over a wire can be 217 returned to you, and they will be turned into references to the same 218 object that you originally sent. The client cannot modify the object 219 in any way: all they can do is point at it and invoke 220 its <code>remote_*</code> methods. Thus, you can be sure that 221 the <code>.name</code> attribute remains the same as you left it. In 222 this case, the client code would look something like this:</p> 218 223 219 224 <pre class="python"> 220 225 class ClientThing(pb.Referenceable): … … 228 233 group.callRemote("send", self.remoteUser, "hi everybody") 229 234 </pre> 230 235 231 <p>The <code>User</code> object is sent from the server side, and is turned 232 into a <code>pb.RemoteReference</code> when it arrives at the client. The 233 client sends it back to <code>Group.remote_send</code>, and PB turns it back 234 into a reference to the original <code>User</code> when it gets there. 235 <code>Group.remote_send</code> can then use its <code>.name</code> attribute 236 as the sender of the message.</p> 236 <p>The <code>User</code> object is sent from the server side, and is 237 turned into a <code>pb.RemoteReference</code> when it arrives at the 238 client. The client sends it back to <code>Group.remote_send</code>, 239 and PB turns it back into a reference to the 240 original <code>User</code> when it gets 241 there. <code>Group.remote_send</code> can then use 242 its <code>.name</code> attribute as the sender of the message.</p> 237 243 238 244 <div class="note"> 239 245 240 246 <p>Third party references (there aren't any)</p> 241 247 242 <p>This technique also relies upon the fact that the 243 <code>pb.Referenceable</code> reference can <em>only</em> come from someone 244 who holds a corresponding <code>pb.RemoteReference</code>. The design of the 245 serialization mechanism (implemented in <code 246 class="API">twisted.spread.jelly</code>: pb, jelly, spread.. get it? Look for 248 <p>This technique also relies upon the fact that 249 the <code>pb.Referenceable</code> reference can <em>only</em> come 250 from someone who holds a 251 corresponding <code>pb.RemoteReference</code>. The design of the 252 serialization mechanism (implemented 253 in <code class="API">twisted.spread.jelly</code>: pb, jelly, 254 spread.. get it? Look for 247 255 <q>banana</q>, too. What other networking framework 248 256 can claim API names based on sandwich ingredients?) makes it impossible for 249 257 a client to obtain a reference that they weren't explicitly given. … … 253 261 will give them anything else. The dict goes away when the connection is 254 262 dropped, further limiting the scope of those references.</p> 255 263 256 <p>Futhermore, it is not possible for Bob to send <em>his</em> 257 <code>User</code> reference to Alice (perhaps over some other PB channel 258 just between the two of them). Outside the context of Bob's connection to 259 the server, that reference is just a meaningless number. To prevent 260 confusion, PB will tell you if you try to give it away: when you try to hand 261 a <code>pb.RemoteReference</code> to a third party, you'll get an exception 262 (implemented with an assert in pb.py:364 RemoteReference.jellyFor).</p> 264 <p>Futhermore, it is not possible for Bob to 265 send <em>his</em> <code>User</code> reference to Alice (perhaps over 266 some other PB channel just between the two of them). Outside the 267 context of Bob's connection to the server, that reference is just a 268 meaningless number. To prevent confusion, PB will tell you if you try 269 to give it away: when you try to hand 270 a <code>pb.RemoteReference</code> to a third party, you'll get an 271 exception (implemented with an assert in pb.py:364 272 RemoteReference.jellyFor).</p> 263 273 264 274 <p>This helps the security model somewhat: only the client you gave the 265 275 reference to can cause any damage with it. Of course, the client might be a … … 286 296 </div> 287 297 288 298 289 <p>But again, note the vulnerability. If Alice holds a 290 <code>RemoteReference</code> to <em>any</em> object on the server side that 291 has a <code>.name</code> attribute, she can use that name as a spoofed 299 <p>But again, note the vulnerability. If Alice holds 300 a <code>RemoteReference</code> to <em>any</em> object on the server 301 side that has a <code>.name</code> attribute, she can use that name as 302 a spoofed 292 303 <q>from</q> parameter. As a simple example, what if her client code looked 293 304 like:</p> 294 305 … … 312 323 313 324 <h3>Argument Typechecking</h3> 314 325 315 <p>There are two techniques to close this hole. The first is to have your 316 remotely-invokable methods do type-checking on their arguments: if 317 <code>Group.remote_send</code> asserted <code>isinstance(from_user, 318 User)</code> then Alice couldn't use non-User objects to do her spoofing, 319 and hopefully the rest of the system is designed well enough to prevent her 320 from obtaining access to somebody else's User object.</p> 326 <p>There are two techniques to close this hole. The first is to have 327 your remotely-invokable methods do type-checking on their arguments: 328 if <code>Group.remote_send</code> asserted <code>isinstance(from_user, 329 User)</code> then Alice couldn't use non-User objects to do her 330 spoofing, and hopefully the rest of the system is designed well enough 331 to prevent her from obtaining access to somebody else's User 332 object.</p> 321 333 322 334 323 335 <h3>Objects as Capabilities</h3> 324 336 325 <p>The second technique is to avoid having the client send you the objects 326 altogether. If they don't send you anything, there is nothing to verify. In 327 this case, you would have to have a per-user-per-group object, in which the 328 <code>remote_send</code> method would only take a single 329 <code>message</code> argument. The <code>UserGroup</code> object is created 330 with references to the only <code>User</code> and <code>Group</code> objects 331 that it will ever use, so no lookups are needed:</p> 337 <p>The second technique is to avoid having the client send you the 338 objects altogether. If they don't send you anything, there is nothing 339 to verify. In this case, you would have to have a per-user-per-group 340 object, in which the <code>remote_send</code> method would only take a 341 single <code>message</code> argument. The <code>UserGroup</code> 342 object is created with references to the only <code>User</code> 343 and <code>Group</code> objects that it will ever use, so no lookups 344 are needed:</p> 332 345 333 346 <pre class="python"> 334 347 class UserGroup(pb.Referenceable): … … 352 365 self.users.append(user) 353 366 </pre> 354 367 355 <p>The only message-sending method Alice has left is356 <code>UserGroup.remote_send</code>, and it only accepts a message: there are 357 no remaining ways to influence the <q>from</q> name.</p>368 <p>The only message-sending method Alice has left 369 is <code>UserGroup.remote_send</code>, and it only accepts a message: 370 there are no remaining ways to influence the <q>from</q> name.</p> 358 371 359 372 <p>In this model, each remotely-accessible object represents a very small 360 373 set of capabilities. Security is achieved by only granting a minimal set of 361 374 abilities to each remote user.</p> 362 375 363 <p>PB provides a shortcut which makes this technique easier to use. The364 <code>Viewable</code> class will be discussed <a 365 href="#viewable">below</a>.</p>376 <p>PB provides a shortcut which makes this technique easier to 377 use. The <code>Viewable</code> class will be 378 discussed <a href="#viewable">below</a>.</p> 366 379 367 380 <h2>Avatars and Perspectives</h2> 368 381 … … 380 393 <q>what serves as the Avatar?</q>, and <q>how does the user get access to 381 394 it?</q>.</p> 382 395 383 <p>For PB, the first question is easy. The Avatar is a remotely-accessible384 object which can run code: this is a perfect description of 385 <code>pb.Referenceable</code> and its subclasses. We shall defer the second 386 question until the next section.</p>396 <p>For PB, the first question is easy. The Avatar is a 397 remotely-accessible object which can run code: this is a perfect 398 description of <code>pb.Referenceable</code> and its subclasses. We 399 shall defer the second question until the next section.</p> 387 400 388 <p>In the example above, you can think of the <code>ChatServer</code> and 389 <code>Group</code> objects as a service. The <code>User</code> object is the 390 user's server-side representative: everything the user is capable of doing 391 is done by running one of its methods. Anything that the server wants to do 392 to the user (change their group membership, change their name, delete their 393 pet cat, whatever) is done by manipulating the <code>User</code> object.</p> 401 <p>In the example above, you can think of the <code>ChatServer</code> 402 and <code>Group</code> objects as a service. The <code>User</code> 403 object is the user's server-side representative: everything the user 404 is capable of doing is done by running one of its methods. Anything 405 that the server wants to do to the user (change their group 406 membership, change their name, delete their pet cat, whatever) is done 407 by manipulating the <code>User</code> object.</p> 394 408 395 409 <p>There are multiple User objects living in peace and harmony around the 396 410 ChatServer. Each has a different point of view on the services provided by … … 400 414 origin of the term <q>Perspective</q> in <q>Perspective Broker</q>: PB 401 415 provides and controls (i.e. <q>brokers</q>) access to Perspectives.</p> 402 416 403 <p>Once upon a time, these local-representative objects were actually called 404 <code>pb.Perspective</code>. But this has changed with the advent of the 405 rewritten cred system, and now the more generic term for a local 406 representative object is an Avatar. But you will still see reference to 417 <p>Once upon a time, these local-representative objects were actually 418 called <code>pb.Perspective</code>. But this has changed with the 419 advent of the rewritten cred system, and now the more generic term for 420 a local representative object is an Avatar. But you will still see 421 reference to 407 422 <q>Perspective</q> in the code, the docs, and the module names<span 408 423 class="footnote">We could just go ahead and rename Perspective Broker to be 409 424 Avatar Broker, but 1) that would cause massive compatibility problems, and 2) … … 414 429 the whole food-pun thing would start all over again.</span>. Just remember 415 430 that perspectives and avatars are basically the same thing. </p> 416 431 417 <p>Despite all we've been <a href="cred.xhtml">telling you</a> about how 418 Avatars are more of a concept than an actual class, the base class from 419 which you can create your server-side avatar-ish objects is, in fact, named 420 <code>pb.Avatar</code><span class="footnote">The avatar-ish class is named 421 <code>pb.Avatar</code> because <code>pb.Perspective</code> was already 422 taken, by the (now obsolete) oldcred perspective-ish class. It is a pity, 423 but it simply wasn't possible both replace <code>pb.Perspective</code> 432 <p>Despite all we've been <a href="cred.xhtml">telling you</a> about 433 how Avatars are more of a concept than an actual class, the base class 434 from which you can create your server-side avatar-ish objects is, in 435 fact, named <code>pb.Avatar</code><span class="footnote">The 436 avatar-ish class is named <code>pb.Avatar</code> 437 because <code>pb.Perspective</code> was already taken, by the (now 438 obsolete) oldcred perspective-ish class. It is a pity, but it simply 439 wasn't possible both replace <code>pb.Perspective</code> 424 440 in-place <em>and</em> maintain a reasonable level of 425 backwards-compatibility.</span>. These objects behave very much like 426 <code>pb.Referenceable</code>. The only difference is that instead of 427 offering <q>remote_FOO</q> methods, they offer <q>perspective_FOO</q> 428 methods.</p> 429 430 <p>The other way in which <code>pb.Avatar</code> differs from 431 <code>pb.Referenceable</code> is that the avatar objects are designed to be 432 the first thing retrieved by a cred-using remote client. Just as 433 <code>PBClientFactory.getRootObject</code> gives the client access to a 434 <code>pb.Root</code> object (which can then provide access to all kinds of 435 other objects), <code>PBClientFactory.login</code> gives client access to a 436 <code>pb.Avatar</code> object (which can return other references). </p> 441 backwards-compatibility.</span>. These objects behave very much 442 like <code>pb.Referenceable</code>. The only difference is that 443 instead of offering <q>remote_FOO</q> methods, they 444 offer <q>perspective_FOO</q> methods.</p> 445 446 <p>The other way in which <code>pb.Avatar</code> differs 447 from <code>pb.Referenceable</code> is that the avatar objects are 448 designed to be the first thing retrieved by a cred-using remote 449 client. Just as <code>PBClientFactory.getRootObject</code> gives the 450 client access to a <code>pb.Root</code> object (which can then provide 451 access to all kinds of other 452 objects), <code>PBClientFactory.login</code> gives client access to 453 a <code>pb.Avatar</code> object (which can return other 454 references). </p> 437 455 438 456 <p>So, the first half of using cred in your PB application is to create an 439 457 Avatar object which implements <code>perspective_</code> methods and is … … 488 506 <div class="note"> 489 507 490 508 <p>When the client runs <code>login</code> to request the Perspective, 491 they can provide it with an optional <code>client</code> argument (which 492 must be a <code>pb.Referenceable</code> object). If they do, then a 493 reference to that object will be handed to the realm's 494 <code>requestAvatar</code> in the <code>mind</code> argument.</p> 509 they can provide it with an optional <code>client</code> argument 510 (which must be a <code>pb.Referenceable</code> object). If they do, 511 then a reference to that object will be handed to the 512 realm's <code>requestAvatar</code> in the <code>mind</code> 513 argument.</p> 495 514 496 515 <p>The server-side Perspective can use it to invoke remote methods on 497 516 something in the client, so that the client doesn't always have to drive the … … 522 541 our server-side Avatar. It implements a <code>perspective_foo</code> method 523 542 that is exposed to the remote client.</p> 524 543 525 <p>Second, we created a realm (an object which implements 526 <code>IRealm</code>, and therefore implements <code>requestAvatar</code>). 527 This realm manufactures <code>MyPerspective</code> objects. It makes as many 528 as we want, and names each one with the avatarID (a username) that comes out 529 of the checkers. This MyRealm object returns two other objects as well, 530 which we will describe later.</p> 544 <p>Second, we created a realm (an object which 545 implements <code>IRealm</code>, and therefore 546 implements <code>requestAvatar</code>). This realm 547 manufactures <code>MyPerspective</code> objects. It makes as many as 548 we want, and names each one with the avatarID (a username) that comes 549 out of the checkers. This MyRealm object returns two other objects as 550 well, which we will describe later.</p> 531 551 532 552 <p>Third, we created a portal to hold this realm. The portal's job is to 533 553 dispatch incoming clients to the credential checkers, and then to request 534 554 Avatars for any which survive the authentication process.</p> 535 555 536 <p>Fourth, we made a simple checker (an object which implements537 <code>IChecker</code>) to hold valid user/password pairs. The checker 538 gets registered with the portal, so it knows who to ask when new 539 clients connect. We use a checker named 540 <code>InMemoryUsernamePasswordDatabaseDontUse</code>, which suggests 541 that 1: all the username/password pairs are kept in memory instead of 542 being saved to a database or something, and 2: you shouldn't use 543 it. The admonition against using it is because there are better 544 schemes: keeping everything in memory will not work when you have 545 thousands or millions of users to keep track of, the passwords will be 546 stored in the .tap file when the application shuts down (possibly a 547 security risk), and finally it is a nuisance to add or remove users 548 after the checker is constructed.</p>556 <p>Fourth, we made a simple checker (an object which 557 implements <code>IChecker</code>) to hold valid user/password 558 pairs. The checker gets registered with the portal, so it knows who to 559 ask when new clients connect. We use a checker 560 named <code>InMemoryUsernamePasswordDatabaseDontUse</code>, which 561 suggests that 1: all the username/password pairs are kept in memory 562 instead of being saved to a database or something, and 2: you 563 shouldn't use it. The admonition against using it is because there are 564 better schemes: keeping everything in memory will not work when you 565 have thousands or millions of users to keep track of, the passwords 566 will be stored in the .tap file when the application shuts down 567 (possibly a security risk), and finally it is a nuisance to add or 568 remove users after the checker is constructed.</p> 549 569 550 570 <p>Fifth, we create a <code>pb.PBServerFactory</code> to listen on a TCP 551 571 port. This factory knows how to connect the remote client to the Portal, so … … 554 574 Protocol objects will give those objects access to the Portal so 555 575 authentication can take place.</p> 556 576 557 <p>On the client side, a <code>pb.PBClientFactory</code> is created (as <a 558 href="pb-usage.xhtml">before</a>) and attached to a TCP connection. When the 559 connection completes, the factory will be asked to produce a Protocol, and 560 it will create a PB object. Unlike the previous chapter, where we used 561 <code>.getRootObject</code>, here we use <code>factory.login</code> to 562 initiate the cred authentication process. We provide a 563 <code>credentials</code> object, which is the client-side agent for doing 564 our half of the authentication process. This process may involve several 565 messages: challenges, responses, encrypted passwords, secure hashes, etc. We 566 give our credentials object everything it will need to respond correctly (in 567 this case, a username and password, but you could write a credential that 568 used public-key encryption or even fancier techniques).</p> 569 570 <p><code>login</code> returns a Deferred which, when it fires, will return a 571 <code>pb.RemoteReference</code> to the remote avatar. We can then do 572 <code>callRemote</code> to invoke a <code>perspective_foo</code> method on 577 <p>On the client side, a <code>pb.PBClientFactory</code> is created 578 (as <a href="pb-usage.xhtml">before</a>) and attached to a TCP 579 connection. When the connection completes, the factory will be asked 580 to produce a Protocol, and it will create a PB object. Unlike the 581 previous chapter, where we used <code>.getRootObject</code>, here we 582 use <code>factory.login</code> to initiate the cred authentication 583 process. We provide a <code>credentials</code> object, which is the 584 client-side agent for doing our half of the authentication 585 process. This process may involve several messages: challenges, 586 responses, encrypted passwords, secure hashes, etc. We give our 587 credentials object everything it will need to respond correctly (in 588 this case, a username and password, but you could write a credential 589 that used public-key encryption or even fancier techniques).</p> 590 591 <p><code>login</code> returns a Deferred which, when it fires, will 592 return a <code>pb.RemoteReference</code> to the remote avatar. We can 593 then do <code>callRemote</code> to invoke a <code>perspective_foo</code> method on 573 594 that Avatar.</p> 574 595 575 596 … … 578 599 <a href="listings/pb/pbAnonServer.py" class="py-listing">pbAnonServer.py</a> 579 600 <a href="listings/pb/pbAnonClient.py" class="py-listing">pbAnonClient.py</a> 580 601 581 <p>pbAnonServer.py implements a server based on pb6server.py, extending it to 582 permit anonymous logins in addition to authenticated logins. A 583 <code class="API" base="twisted.cred.checkers">AllowAnonymousAccess</code> 584 checker and a <code class="API" base="twisted.cred.checkers"> 585 InMemoryUsernamePasswordDatabaseDontUse</code> checker are registered and the 586 client's choice of credentials object determines which is used to authenticate 587 the login. In either case, the realm will be called on to create an avatar for 588 the login. <code>AllowAnonymousAccess</code> always produces an <code>avatarId 589 </code> of <code class="API" base="twisted.cred.checkers">ANONYMOUS</code>.</p> 590 591 <p>On the client side, the only change is the use of an instance of 592 <code class="API" base="twisted.cred.credentials">Anonymous</code> when calling 593 <code class="API" base="twisted.spread.pb">PBClientFactory.login</code>.</p> 602 <p>pbAnonServer.py implements a server based on pb6server.py, 603 extending it to permit anonymous logins in addition to authenticated 604 logins. A <code class="API" 605 base="twisted.cred.checkers">AllowAnonymousAccess</code> checker and 606 a <code class="API" base="twisted.cred.checkers"> 607 InMemoryUsernamePasswordDatabaseDontUse</code> checker are registered 608 and the client's choice of credentials object determines which is used 609 to authenticate the login. In either case, the realm will be called 610 on to create an avatar for the 611 login. <code>AllowAnonymousAccess</code> always produces 612 an <code>avatarId</code> of <code class="API" 613 base="twisted.cred.checkers">ANONYMOUS</code>.</p> 614 615 <p>On the client side, the only change is the use of an instance 616 of <code class="API" base="twisted.cred.credentials">Anonymous</code> 617 when calling <code class="API" 618 base="twisted.spread.pb">PBClientFactory.login</code>.</p> 594 619 595 620 596 621 <h2>Using Avatars</h2> … … 619 644 620 645 <h3>Making Avatars</h3> 621 646 622 <p>In the example above, we create Avatars upon request, during 623 <code>requestAvatar</code>. Depending upon the service, these Avatars might 624 already exist before the connection is received, and might outlive the 625 connection. The Avatars might also accept multiple connections.</p> 647 <p>In the example above, we create Avatars upon request, 648 during <code>requestAvatar</code>. Depending upon the service, these 649 Avatars might already exist before the connection is received, and 650 might outlive the connection. The Avatars might also accept multiple 651 connections.</p> 626 652 627 653 <p>Another possibility is that the Avatars might exist ahead of time, but in 628 654 a different form (frozen in a pickle and/or saved in a database). In this … … 631 657 case, it would probably return a Deferred so it could provide the real 632 658 Avatar later, once the lookup had completed.</p> 633 659 634 <p>Here are some possible implementations of635 <code>MyRealm.requestAvatar</code>:</p>660 <p>Here are some possible implementations 661 of <code>MyRealm.requestAvatar</code>:</p> 636 662 637 663 <pre class="python"> 638 664 # pre-existing, static avatars … … 690 716 them (through the <q>mind</q> argument which lets the Avatar do callRemote 691 717 on the client).</p> 692 718 693 <p>One common idiom which accomplishes this is to have the Realm tell the694 avatar that a remote client has just attached. The Realm can also ask the 695 protocol to let it know when the connection goes away, so it can then inform 696 the Avatar that the client has detached. The third member of the 697 <code>requestAvatar</code> return tuple is a callable which will be invoked 698 wh en the connection is lost.</p>719 <p>One common idiom which accomplishes this is to have the Realm tell 720 the avatar that a remote client has just attached. The Realm can also 721 ask the protocol to let it know when the connection goes away, so it 722 can then inform the Avatar that the client has detached. The third 723 member of the <code>requestAvatar</code> return tuple is a callable 724 which will be invoked when the connection is lost.</p> 699 725 700 726 <pre class="python"> 701 727 class MyPerspective(pb.Avatar): … … 722 748 723 749 <h3>Viewable</h3> <a name="viewable" /> 724 750 725 <p>Once you have <code>IPerspective</code> objects (i.e. the Avatar) to 726 represent users, the <code class="API" 727 base="twisted.spread.flavors">Viewable</code> class can come into play. This 728 class behaves a lot like <code>Referenceable</code>: it turns into a 729 <code>RemoteReference</code> when sent over the wire, and certain methods 730 can be invoked by the holder of that reference. However, the methods that 731 can be called have names that start with <code>view_</code> instead of 732 <code>remote_</code>, and those methods are always called with an extra 733 <code>perspective</code> argument that points to the Avatar through which 734 the reference was sent:</p> 751 <p>Once you have <code>IPerspective</code> objects (i.e. the Avatar) 752 to represent users, the <code class="API" 753 base="twisted.spread.flavors">Viewable</code> class can come into 754 play. This class behaves a lot like <code>Referenceable</code>: it 755 turns into a <code>RemoteReference</code> when sent over the wire, and 756 certain methods can be invoked by the holder of that 757 reference. However, the methods that can be called have names that 758 start with <code>view_</code> instead of <code>remote_</code>, and 759 those methods are always called with an extra <code>perspective</code> 760 argument that points to the Avatar through which the reference was 761 sent:</p> 735 762 736 763 <pre class="python"> 737 764 class Foo(pb.Viewable): … … 745 772 gives them a way to do additional permission checks, do per-user accounting, 746 773 etc.</p> 747 774 748 <p>This is the shortcut which makes per-user-per-group capability objects 749 much easier to use. Instead of creating such per-(user,group) objects, you 750 just have per-group objects which inherit from <code>pb.Viewable</code>, and 751 give the user references to them. The local <code>pb.Avatar</code> object 752 will automatically show up as the <q>perspective</q> argument in the 753 <code>view_*</code> method calls, give you a chance to involve the Avatar in 754 the process.</p> 775 <p>This is the shortcut which makes per-user-per-group capability 776 objects much easier to use. Instead of creating such per-(user,group) 777 objects, you just have per-group objects which inherit 778 from <code>pb.Viewable</code>, and give the user references to 779 them. The local <code>pb.Avatar</code> object will automatically show 780 up as the <q>perspective</q> argument in the <code>view_*</code> 781 method calls, give you a chance to involve the Avatar in the 782 process.</p> 755 783 756 784 757 785 <h3>Chat Server with Avatars</h3> … … 764 792 765 793 <a href="listings/pb/chatserver.py" class="py-listing">chatserver.py</a> 766 794 767 <p>Notice that the client uses <code>perspective_joinGroup</code> to both 768 join a group and retrieve a <code>RemoteReference</code> to the 769 <code>Group</code> object. However, the reference they get is actually to a 770 special intermediate object called a <code>pb.ViewPoint</code>. When they do 771 <code>group.callRemote("send", "message")</code>, their avatar is inserted 772 into the argument list that <code>Group.view_send</code> actually sees. This 773 lets the group get their username out of the Avatar without giving the 774 client an opportunity to spoof someone else.</p> 795 <p>Notice that the client uses <code>perspective_joinGroup</code> to 796 both join a group and retrieve a <code>RemoteReference</code> to 797 the <code>Group</code> object. However, the reference they get is 798 actually to a special intermediate object called 799 a <code>pb.ViewPoint</code>. When they 800 do <code>group.callRemote("send", "message")</code>, their avatar is 801 inserted into the argument list that <code>Group.view_send</code> 802 actually sees. This lets the group get their username out of the 803 Avatar without giving the client an opportunity to spoof someone 804 else.</p> 775 805 776 806 <p>The client side code that joins a group and sends a message would look 777 807 like this:</p> -
doc/core/howto/pb-intro.xhtml
diff --git a/doc/core/howto/pb-intro.xhtml b/doc/core/howto/pb-intro.xhtml index 6d976c8..2350830 100644
a b 55 55 56 56 <ul> 57 57 58 <li>< em><code class="API" base="twisted.internet.protocol">Factory</code></em>58 <li><code class="API" base="twisted.internet.protocol">Factory</code> 59 59 : <code>internet/protocol.py</code></li> 60 60 61 <li>< em><code class="API" base="twisted.spread.pb">PBServerFactory</code></em>61 <li><code class="API" base="twisted.spread.pb">PBServerFactory</code> 62 62 : <code>spread/pb.py</code></li> 63 63 64 <li>< em><code class="API" base="twisted.spread.pb">Broker</code></em>64 <li><code class="API" base="twisted.spread.pb">Broker</code> 65 65 : <code>spread/pb.py</code></li> 66 66 67 67 </ul> … … 70 70 71 71 <ul> 72 72 73 <li> <em><code class="API" base="twisted.spread.pb">RemoteReference</code></em>73 <li><code class="API" base="twisted.spread.pb">RemoteReference</code> 74 74 : <code>spread/pb.py</code> </li> 75 75 76 <li> <em><code class="API" base="twisted.spread">pb.Root</code></em>76 <li><code class="API" base="twisted.spread">pb.Root</code> 77 77 : <code>spread/pb.py</code>, actually defined as 78 78 <code>twisted.spread.flavors.Root</code> 79 79 in <code>spread/flavors.py</code> </li> 80 80 81 <li> <em><code class="API" base="twisted.spread">pb.Referenceable</code></em>81 <li><code class="API" base="twisted.spread">pb.Referenceable</code> 82 82 : <code>spread/pb.py</code>, actually defined as 83 83 <code>twisted.spread.flavors.Referenceable</code> 84 84 in <code>spread/flavors.py</code> </li> … … 89 89 about authorization and security:</p> 90 90 91 91 <ul> 92 <li>< em><code class="API" base="twisted.cred.portal">Portal</code></em>92 <li><code class="API" base="twisted.cred.portal">Portal</code> 93 93 : <code>cred/portal.py</code></li> 94 94 95 <li>< em><code class="API" base="twisted.cred.portal">IRealm</code></em>95 <li><code class="API" base="twisted.cred.portal">IRealm</code> 96 96 : <code>cred/portal.py</code></li> 97 97 98 <li>< em><code class="API" base="twisted.spread.pb">IPerspective</code></em>98 <li><code class="API" base="twisted.spread.pb">IPerspective</code> 99 99 : <code>spread/pb.py</code>, which you will usually be interacting 100 100 with via pb.Avatar (a basic implementor of the interface).</li> 101 101 </ul> … … 205 205 <p>In addition to returning objects that you can call remote methods on, you 206 206 can return structured copies of local objects.</p> 207 207 208 <p>There are 2 basic flavors that allow for copying objects remotely. Again,209 you can use these by subclassing them. In order to specify what state you want 210 to have copied when these are serialized, you can either use the Python default 211 <code class="python">__getstate__</code> or specialized method calls for that 212 flavor.</p>208 <p>There are 2 basic flavors that allow for copying objects remotely. 209 Again, you can use these by subclassing them. In order to specify 210 what state you want to have copied when these are serialized, you can 211 either use the Python default <code class="python">__getstate__</code> 212 or specialized method calls for that flavor.</p> 213 213 214 214 <p> 215 215 <ul> -
doc/core/howto/pb-limits.xhtml
diff --git a/doc/core/howto/pb-limits.xhtml b/doc/core/howto/pb-limits.xhtml index f0e6204..24b49c8 100644
a b 30 30 It's possible to raise this limit by changing this value (but take care to 31 31 change it on both sides of the connection).</p> 32 32 33 <p>Another limit imposed by Twisted's Banana implementation is a limit on 34 the size of long integers. The purpose of this limit is the same as the 35 <code>SIZE_LIMIT</code>. By default, only integers between -2 ** 448 and 2 36 ** 448 (exclusive) can be transferred. This limit can be changed using 37 <code class="API">twisted.spread.banana.setPrefixLimit</code>.</p> 33 <p>Another limit imposed by Twisted's Banana implementation is a 34 limit on the size of long integers. The purpose of this limit is the 35 same as the <code>SIZE_LIMIT</code>. By default, only integers 36 between -2 ** 448 and 2 ** 448 (exclusive) can be transferred. This 37 limit can be changed 38 using <code class="API">twisted.spread.banana.setPrefixLimit</code>.</p> 38 39 39 40 <h2>Perspective Broker Limits</h2> 40 41 -
doc/core/howto/pb-usage.xhtml
diff --git a/doc/core/howto/pb-usage.xhtml b/doc/core/howto/pb-usage.xhtml index c602e8a..924f9ab 100644
a b 9 9 10 10 <h2>Basic Example</h2> 11 11 12 <p>The first example to look at is a complete (although somewhat trivial) 13 application. It uses <code>PBServerFactory()</code> on the server side, and 14 <code>PBClientFactory()</code> on the client side.</p> 12 <p>The first example to look at is a complete (although somewhat 13 trivial) application. It uses <code>PBServerFactory()</code> on the 14 server side, and <code>PBClientFactory()</code> on the client 15 side.</p> 15 16 16 17 <a href="../examples/pbsimple.py" class="py-listing" skipLines="5" 17 18 >pbsimple.py</a> 18 19 <a href="../examples/pbsimpleclient.py" class="py-listing" skipLines="5" 19 20 >pbsimpleclient.py</a> 20 21 21 <p>First we look at the server. This defines an Echoer class (derived from 22 <code class="API" base="twisted.spread">pb.Root</code>), with a method called 23 <code>remote_echo()</code>. 24 <code class="API" base="twisted.spread">pb.Root</code> objects (because of 25 their inheritance of 26 <code class="API" base="twisted.spread">pb.Referenceable</code>, described 27 later) can define methods with names of the form <code>remote_*</code>; a 28 client which obtains a remote reference to that 29 <code class="API" base="twisted.spread">pb.Root</code> object will be able to 30 invoke those methods.</p> 31 32 <p>The <code class="API" base="twisted.spread">pb.Root</code>-ish object is 33 given to a <code class="API" 34 base="twisted.spread">pb.PBServerFactory</code><code>()</code>. This is a 35 <code class="API" base="twisted.internet.protocol">Factory</code> object like 36 any other: the <code class="API" 37 base="twisted.internet.protocol">Protocol</code> objects it creates for new 38 connections know how to speak the PB protocol. The object you give to 39 <code>pb.PBServerFactory()</code> becomes the <q>root object</q>, which 40 simply makes it available for the client to retrieve. The client may only 41 request references to the objects you want to provide it: this helps you 42 implement your security model. Because it is so common to export just a 43 single object (and because a <code>remote_*</code> method on that one can 44 return a reference to any other object you might want to give out), the 22 <p>First we look at the server. This defines an Echoer class (derived 23 from <code class="API" base="twisted.spread">pb.Root</code>), with a 24 method called <code>remote_echo()</code>. <code class="API" 25 base="twisted.spread">pb.Root</code> objects (because of their 26 inheritance of <code class="API" 27 base="twisted.spread">pb.Referenceable</code>, described later) can 28 define methods with names of the form <code>remote_*</code>; a client 29 which obtains a remote reference to that <code class="API" 30 base="twisted.spread">pb.Root</code> object will be able to invoke 31 those methods.</p> 32 33 <p>The <code class="API" base="twisted.spread">pb.Root</code>-ish 34 object is given to a <code class="API" 35 base="twisted.spread">pb.PBServerFactory</code><code>()</code>. This 36 is a <code class="API" base="twisted.internet.protocol">Factory</code> 37 object like any other: the <code class="API" 38 base="twisted.internet.protocol">Protocol</code> objects it creates 39 for new connections know how to speak the PB protocol. The object you 40 give to <code>pb.PBServerFactory()</code> becomes the <q>root 41 object</q>, which simply makes it available for the client to 42 retrieve. The client may only request references to the objects you 43 want to provide it: this helps you implement your security 44 model. Because it is so common to export just a single object (and 45 because a <code>remote_*</code> method on that one can return a 46 reference to any other object you might want to give out), the 45 47 simplest example is one where the <code class="API" 46 base="twisted.spread.pb">PBServerFactory</code> is given the root object, and47 the client retrieves it.</p>48 base="twisted.spread.pb">PBServerFactory</code> is given the root 49 object, and the client retrieves it.</p> 48 50 49 <p>The client side uses 50 <code class="API" base="twisted.spread">pb.PBClientFactory</code> to make a 51 connection to a given port. This is a two-step process involving opening 52 a TCPconnection to a given host and port and requesting the root object51 <p>The client side uses <code class="API" 52 base="twisted.spread">pb.PBClientFactory</code> to make a connection 53 to a given port. This is a two-step process involving opening a TCP 54 connection to a given host and port and requesting the root object 53 55 using <code>.getRootObject()</code>.</p> 54 56 55 57 <p>Because <code>.getRootObject()</code> has to wait until a network … … 61 63 connection succeeds and a reference to the remote root object is 62 64 obtained, this callback is run. The first argument passed to the 63 65 callback is a remote reference to the distant root object. (you can 64 give other arguments to the callback too, see the other parameters for65 <code>.addCallback()</code> and <code>.addCallbacks()</code>).</p>66 give other arguments to the callback too, see the other parameters 67 for <code>.addCallback()</code> and <code>.addCallbacks()</code>).</p> 66 68 67 69 <p>The callback does:</p> 68 70 … … 70 72 object.callRemote("echo", "hello network") 71 73 </pre> 72 74 73 <p>which causes the server's <code>.remote_echo()</code> method to be invoked. 74 (running <code>.callRemote("boom")</code> would cause 75 <code>.remote_boom()</code> to be run, etc). Again because of the delay 76 involved, <code>callRemote()</code> returns a 77 <code class="API" base="twisted.internet.defer">Deferred</code>. Assuming the 78 remote method was run without causing an exception (including an attempt to 79 invoke an unknown method), the callback attached to that 80 <code class="API" base="twisted.internet.defer">Deferred</code> will be 81 invoked with any objects that were returned by the remote method call.</p> 75 <p>which causes the server's <code>.remote_echo()</code> method to be 76 invoked. (running <code>.callRemote("boom")</code> would 77 cause <code>.remote_boom()</code> to be run, etc). Again because of 78 the delay involved, <code>callRemote()</code> returns 79 a<code class="API" 80 base="twisted.internet.defer">Deferred</code>. Assuming the remote 81 method was run without causing an exception (including an attempt to 82 invoke an unknown method), the callback attached to 83 that <code class="API" base="twisted.internet.defer">Deferred</code> 84 will be invoked with any objects that were returned by the remote 85 method call.</p> 82 86 83 87 <p>In this example, the server's <code>Echoer</code> object has a method 84 88 invoked, <em>exactly</em> as if some code on the server side had done:</p> … … 100 104 breaks down when faced with the asynchronous nature of the network. Using 101 105 Deferreds turns out to be a very clean way to deal with the whole thing.</p> 102 106 103 <p>The remote reference object (the one given to 104 <code>getRootObject()</code>'s success callback) is an instance the <code 105 class="API" base="twisted.spread.pb">RemoteReference</code> class. This means 106 you can use it to invoke methods on the remote object that it refers to. Only 107 instances of <code class="API" 108 base="twisted.spread.pb">RemoteReference</code> are eligible for 109 <code>.callRemote()</code>. The <code class="API" 110 base="twisted.spread.pb">RemoteReference</code> object is the one that lives 111 on the remote side (the client, in this case), not the local side (where the 112 actual object is defined).</p> 113 114 <p>In our example, the local object is that <code>Echoer()</code> instance, 115 which inherits from <code class="API" base="twisted.spread">pb.Root</code>, 116 which inherits from 117 <code class="API" base="twisted.spread">pb.Referenceable</code>. It is that 118 <code>Referenceable</code> class that makes the object eligible to be available 119 for remote method calls<span class="footnote">There are a few other classes 120 that can bestow this ability, but pb.Referenceable is the easiest to 121 understand; see 'flavors' below for details on the others.</span>. If you have 122 an object that is Referenceable, then any client that manages to get a 123 reference to it can invoke any <code>remote_*</code> methods they please.</p> 107 <p>The remote reference object (the one given 108 to <code>getRootObject()</code>'s success callback) is an instance 109 the <code class="API" base="twisted.spread.pb">RemoteReference</code> 110 class. This means you can use it to invoke methods on the remote 111 object that it refers to. Only instances of <code class="API" 112 base="twisted.spread.pb">RemoteReference</code> are eligible 113 for <code>.callRemote()</code>. The <code class="API" 114 base="twisted.spread.pb">RemoteReference</code> object is the one that 115 lives on the remote side (the client, in this case), not the local 116 side (where the actual object is defined).</p> 117 118 <p>In our example, the local object is that <code>Echoer()</code> 119 instance, which inherits from <code class="API" 120 base="twisted.spread">pb.Root</code>, which inherits 121 from <code class="API" 122 base="twisted.spread">pb.Referenceable</code>. It is 123 that <code>Referenceable</code> class that makes the object eligible 124 to be available for remote method calls<span class="footnote">There 125 are a few other classes that can bestow this ability, but 126 pb.Referenceable is the easiest to understand; see 'flavors' below for 127 details on the others.</span>. If you have an object that is 128 Referenceable, then any client that manages to get a reference to it 129 can invoke any <code>remote_*</code> methods they please.</p> 124 130 125 131 <div class="note"> 126 <p>The <em>only</em> thing they can do is invoke those 127 methods. In particular, they cannot access attributes. From a security point 128 of view, you control what they can do by limiting what the 129 <code>remote_*</code> methods can do.</p> 130 131 <p>Also note: the other classes like 132 <code class="API" base="twisted.spread.pb">Referenceable</code> allow access to 133 other methods, in particular <code>perspective_*</code> and <code>view_*</code> 134 may be accessed. Don't write local-only methods with these names, because then 135 remote callers will be able to do more than you intended.</p> 136 137 <p>Also also note: the other classes like 138 <code class="API" base="twisted.spread">pb.Copyable</code> <em>do</em> allow 139 access to attributes, but you control which ones they can see.</p> 132 <p>The <em>only</em> thing they can do is invoke those methods. In 133 particular, they cannot access attributes. From a security point of 134 view, you control what they can do by limiting what 135 the <code>remote_*</code> methods can do.</p> 136 137 <p>Also note: the other classes like <code class="API" 138 base="twisted.spread.pb">Referenceable</code> allow access to other 139 methods, in particular <code>perspective_*</code> 140 and <code>view_*</code> may be accessed. Don't write local-only 141 methods with these names, because then remote callers will be able to 142 do more than you intended.</p> 143 144 <p>Also also note: the other classes like <code class="API" 145 base="twisted.spread">pb.Copyable</code> <em>do</em> allow access to 146 attributes, but you control which ones they can see.</p> 140 147 </div> 141 148 142 <p>You don't have to be a 143 <code class="API" base="twisted.spread">pb.Root</code> to be remotely callable, 144 but you do have to be 145 <code class="API" base="twisted.spread">pb.Referenceable</code>. (Objects that 146 inherit from <code class="API" base="twisted.spread">pb.Referenceable</code> 147 but not from <code class="API" base="twisted.spread">pb.Root</code> can be 148 remotely called, but only 149 <code class="API" base="twisted.spread">pb.Root</code>-ish objects can be given 150 to the <code class="API" base="twisted.spread.pb">PBServerFactory</code>.)</p> 149 <p>You don't have to be a <code class="API" 150 base="twisted.spread">pb.Root</code> to be remotely callable, but you 151 do have to be <code class="API" 152 base="twisted.spread">pb.Referenceable</code>. (Objects that inherit 153 from <code class="API" base="twisted.spread">pb.Referenceable</code> 154 but not from <code class="API" base="twisted.spread">pb.Root</code> 155 can be remotely called, but only <code class="API" 156 base="twisted.spread">pb.Root</code>-ish objects can be given to 157 the <code class="API" 158 base="twisted.spread.pb">PBServerFactory</code>.)</p> 151 159 152 160 <h2>Complete Example</h2> 153 161 … … 166 174 handle all the details of waiting for the creation of a connection. 167 175 It returns a <code class="API" 168 176 base="twisted.internet.defer">Deferred</code>, which will have its 169 callback called when the reactor connects to the remote server and170 <code class="API" base="twisted.spread">pb.PBClientFactory</code> gets the 171 root, and have its <code class="python">errback</code> called when the 172 object-connection fails for any reason, whether it was host lookup 173 failure, connection refusal, or some server-side error.177 callback called when the reactor connects to the remote server 178 and <code class="API" base="twisted.spread">pb.PBClientFactory</code> 179 gets the root, and have its <code class="python">errback</code> called 180 when the object-connection fails for any reason, whether it was host 181 lookup failure, connection refusal, or some server-side error. 174 182 </p> 175 183 176 184 <p>The root object has a method called <code>remote_getTwo</code>, which … … 194 202 will be made, depending on whether an error occurred in processing the 195 203 method call.</p> 196 204 197 <p>You can use this technique to provide access to arbitrary sets of objects. 198 Just remember that any object that might get passed <q>over the wire</q> must 199 inherit from <code class="API" base="twisted.spread.pb">Referenceable</code> 200 (or one of the other flavors). If you try to pass a non-Referenceable object 201 (say, by returning one from a <code>remote_*</code> method), you'll get an 202 <code class="API" base="twisted.spread.jelly">InsecureJelly</code> 203 exception<span class="footnote">This can be overridden, by subclassing one of 204 the Serializable flavors and defining custom serialization code for your 205 class. See <a href="pb-copyable.xhtml">Passing Complex Types</a> for 206 details.</span>.</p> 205 <p>You can use this technique to provide access to arbitrary sets of 206 objects. Just remember that any object that might get passed <q>over 207 the wire</q> must inherit from <code class="API" 208 base="twisted.spread.pb">Referenceable</code> (or one of the other 209 flavors). If you try to pass a non-Referenceable object (say, by 210 returning one from a <code>remote_*</code> method), you'll get 211 an <code class="API" base="twisted.spread.jelly">InsecureJelly</code> 212 exception<span class="footnote">This can be overridden, by subclassing 213 one of the Serializable flavors and defining custom serialization code 214 for your class. See <a href="pb-copyable.xhtml">Passing Complex 215 Types</a> for details.</span>.</p> 207 216 208 217 209 218 <h2>References can come back to you</h2> 210 219 211 <p>If your server gives a reference to a client, and then that client gives 212 the reference back to the server, the server will wind up with the same 213 object it gave out originally. The serialization layer watches for returning 214 reference identifiers and turns them into actual objects. You need to stay 215 aware of where the object lives: if it is on your side, you do actual method 216 calls. If it is on the other side, you do 217 <code>.callRemote()</code><span class="footnote">The binary nature of this 218 local vs. remote scheme works because you cannot give RemoteReferences to a 219 third party. If you could, then your object A could go to B, B could give it to 220 C, C might give it back to you, and you would be hard pressed to tell if the 221 object lived in C's memory space, in B's, or if it was really your own object, 222 tarnished and sullied after being handed down like a really ugly picture that 223 your great aunt owned and which nobody wants but which nobody can bear to throw 224 out. Ok, not really like that, but you get the idea.</span>.</p> 220 <p>If your server gives a reference to a client, and then that client 221 gives the reference back to the server, the server will wind up with 222 the same object it gave out originally. The serialization layer 223 watches for returning reference identifiers and turns them into actual 224 objects. You need to stay aware of where the object lives: if it is on 225 your side, you do actual method calls. If it is on the other side, you 226 do <code>.callRemote()</code><span class="footnote">The binary nature 227 of this local vs. remote scheme works because you cannot give 228 RemoteReferences to a third party. If you could, then your object A 229 could go to B, B could give it to C, C might give it back to you, and 230 you would be hard pressed to tell if the object lived in C's memory 231 space, in B's, or if it was really your own object, tarnished and 232 sullied after being handed down like a really ugly picture that your 233 great aunt owned and which nobody wants but which nobody can bear to 234 throw out. Ok, not really like that, but you get the idea.</span>.</p> 225 235 226 236 <a href="listings/pb/pb2server.py" class="py-listing">pb2server.py</a> 227 237 <a href="listings/pb/pb2client.py" class="py-listing">pb2client.py</a> … … 277 287 about when they go wrong? The Python Way is to raise an exception of some 278 288 sort. The Twisted Way is the same.</p> 279 289 280 <p>The only special thing you do is to define your <code>Exception</code> 281 subclass by deriving it from <code class="API" 282 base="twisted.spread">pb.Error</code>. When any remotely-invokable method 283 (like <code>remote_*</code> or <code>perspective_*</code>) raises a 284 <code>pb.Error</code>-derived exception, a serialized form of that Exception 285 object will be sent back over the wire<span class="footnote">To be precise, 286 the Failure will be sent if <em>any</em> exception is raised, not just 287 pb.Error-derived ones. But the server will print ugly error messages if you 288 raise ones that aren't derived from pb.Error.</span>. The other side (which 289 did <code>callRemote</code>) will have the <q><code>errback</code></q> 290 callback run with a <code class="API" 291 base="twisted.python.failure">Failure</code> object that contains a copy of 292 the exception object. This <code>Failure</code> object can be queried to 293 retrieve the error message and a stack traceback.</p> 290 <p>The only special thing you do is to define 291 your <code>Exception</code> subclass by deriving it 292 from <code class="API" base="twisted.spread">pb.Error</code>. When any 293 remotely-invokable method (like <code>remote_*</code> 294 or <code>perspective_*</code>) raises a <code>pb.Error</code>-derived 295 exception, a serialized form of that Exception object will be sent 296 back over the wire<span class="footnote">To be precise, the Failure 297 will be sent if <em>any</em> exception is raised, not just 298 pb.Error-derived ones. But the server will print ugly error messages 299 if you raise ones that aren't derived from pb.Error.</span>. The other 300 side (which did <code>callRemote</code>) will have 301 the <q><code>errback</code></q> callback run with a <code class="API" 302 base="twisted.python.failure">Failure</code> object that contains a 303 copy of the exception object. This <code>Failure</code> object can be 304 queried to retrieve the error message and a stack traceback.</p> 294 305 295 306 <p><code class="API" base="twisted.python.failure">Failure</code> is a 296 307 special class, defined in <code>twisted/python/failure.py</code>, created to … … 299 310 can't handle the particular type of failure, it can be <q>passed along</q> to a 300 311 errback handler further down the chain.</p> 301 312 302 <p>For simple purposes, think of the <code>Failure</code> as just a container 303 for remotely-thrown <code>Exception</code> objects. To extract the string that 304 was put into the exception, use its <code>.getErrorMessage()</code> method. 305 To get the type of the exception (as a string), look at its 306 <code>.type</code> attribute. The stack traceback is available too. The 307 intent is to let the errback function get just as much information about the 308 exception as Python's normal <code>try:</code> clauses do, even though the 309 exception occurred in somebody else's memory space at some unknown time in 310 the past.</p> 313 <p>For simple purposes, think of the <code>Failure</code> as just a 314 container for remotely-thrown <code>Exception</code> objects. To 315 extract the string that was put into the exception, use 316 its <code>.getErrorMessage()</code> method. To get the type of the 317 exception (as a string), look at its <code>.type</code> attribute. The 318 stack traceback is available too. The intent is to let the errback 319 function get just as much information about the exception as Python's 320 normal <code>try:</code> clauses do, even though the exception 321 occurred in somebody else's memory space at some unknown time in the 322 past.</p> 311 323 312 324 <a href="listings/pb/exc_server.py" class="py-listing">exc_server.py</a> 313 325 <a href="listings/pb/exc_client.py" class="py-listing">exc_client.py</a> … … 321 333 Main loop terminated. 322 334 </pre> 323 335 324 <p>Oh, and what happens if you raise some other kind of exception? Something 325 that <em>isn't</em> subclassed from <code>pb.Error</code>? Well, those are 326 called <q>unexpected exceptions</q>, which make Twisted think that something 327 has <em>really</em> gone wrong. These will raise an exception on the 328 <em>server</em> side. This won't break the connection (the exception is 329 trapped, just like most exceptions that occur in response to network 330 traffic), but it will print out an unsightly stack trace on the server's 331 stderr with a message that says <q>Peer Will Receive PB Traceback</q>, just 332 as if the exception had happened outside a remotely-invokable method. (This 333 message will go the current log target, if <code class="API" 334 base="twisted.python">log.startLogging</code> was used to redirect it). The 335 client will get the same <code>Failure</code> object in either case, but 336 subclassing your exception from <code>pb.Error</code> is the way to tell 337 Twisted that you expect this sort of exception, and that it is ok to just 338 let the client handle it instead of also asking the server to complain. Look 339 at <code>exc_client.py</code> and change it to invoke <code>broken2()</code> 340 instead of <code>broken()</code> to see the change in the server's 341 behavior.</p> 342 343 <p>If you don't add an <code>errback</code> function to the <code 344 class="API" base="twisted.internet.defer">Deferred</code>, then a remote 345 exception will still send a <code>Failure</code> object back over, but it 346 will get lodged in the <code>Deferred</code> with nowhere to go. When that 347 <code>Deferred</code> finally goes out of scope, the side that did 348 <code>callRemote</code> will emit a message about an <q>Unhandled error in 349 Deferred</q>, along with an ugly stack trace. It can't raise an exception at 350 that point (after all, the <code>callRemote</code> that triggered the 351 problem is long gone), but it will emit a traceback. So be a good programmer 352 and <em>always add <code>errback</code> handlers</em>, even if they are just 353 calls to <code class="API" base="twisted.python">log.err</code>.</p> 336 <p>Oh, and what happens if you raise some other kind of exception? 337 Something that <em>isn't</em> subclassed from <code>pb.Error</code>? 338 Well, those are called <q>unexpected exceptions</q>, which make 339 Twisted think that something has <em>really</em> gone wrong. These 340 will raise an exception on the <em>server</em> side. This won't break 341 the connection (the exception is trapped, just like most exceptions 342 that occur in response to network traffic), but it will print out an 343 unsightly stack trace on the server's stderr with a message that 344 says <q>Peer Will Receive PB Traceback</q>, just as if the exception 345 had happened outside a remotely-invokable method. (This message will 346 go the current log target, if <code class="API" 347 base="twisted.python">log.startLogging</code> was used to redirect 348 it). The client will get the same <code>Failure</code> object in 349 either case, but subclassing your exception from <code>pb.Error</code> 350 is the way to tell Twisted that you expect this sort of exception, and 351 that it is ok to just let the client handle it instead of also asking 352 the server to complain. Look at <code>exc_client.py</code> and change 353 it to invoke <code>broken2()</code> instead of <code>broken()</code> 354 to see the change in the server's behavior.</p> 355 356 <p>If you don't add an <code>errback</code> function to 357 the <code class="API" base="twisted.internet.defer">Deferred</code>, 358 then a remote exception will still send a <code>Failure</code> object 359 back over, but it will get lodged in the <code>Deferred</code> with 360 nowhere to go. When that <code>Deferred</code> finally goes out of 361 scope, the side that did <code>callRemote</code> will emit a message 362 about an <q>Unhandled error in Deferred</q>, along with an ugly stack 363 trace. It can't raise an exception at that point (after all, 364 the <code>callRemote</code> that triggered the problem is long gone), 365 but it will emit a traceback. So be a good programmer and <em>always 366 add </em> <code>errback</code> <em> handlers</em>, even if they are just calls 367 to <code class="API" base="twisted.python">log.err</code>.</p> 354 368 355 369 <h2>Try/Except blocks and <code class="API" 356 370 base="twisted.python.failure">Failure.trap</code> </h2> 357 371 358 <p>To implement the equivalent of the Python try/except blocks (which can 359 trap particular kinds of exceptions and pass others <q>up</q> to 360 higher-level <code>try/except</code> blocks), you can use the 361 <code>.trap()</code> method in conjunction with multiple 362 <code>errback</code> handlers on the <code>Deferred</code>. Re-raising an 363 exception in an <code>errback</code> handler serves to pass that new 364 exception to the next handler in the chain. The <code>trap</code> method is 365 given a list of exceptions to look for, and will re-raise anything that 366 isn't on the list. Instead of passing unhandled exceptions <q>up</q> to an 372 <p>To implement the equivalent of the Python try/except blocks (which 373 can trap particular kinds of exceptions and pass others <q>up</q> to 374 higher-level <code>try/except</code> blocks), you can use 375 the <code>.trap()</code> method in conjunction with 376 multiple <code>errback</code> handlers on 377 the <code>Deferred</code>. Re-raising an exception in 378 an <code>errback</code> handler serves to pass that new exception to 379 the next handler in the chain. The <code>trap</code> method is given a 380 list of exceptions to look for, and will re-raise anything that isn't 381 on the list. Instead of passing unhandled exceptions <q>up</q> to an 367 382 enclosing <code>try</code> block, this has the effect of passing the 368 exception <q>off</q> to later <code>errback</code> handlers on the same369 <code>Deferred</code>. The <code>trap</code> calls are used in chained 370 errbacks to test for each kind of exception in sequence. </p>383 exception <q>off</q> to later <code>errback</code> handlers on the 384 same <code>Deferred</code>. The <code>trap</code> calls are used in 385 chained errbacks to test for each kind of exception in sequence. </p> 371 386 372 387 <a href="listings/pb/trap_server.py" class="py-listing">trap_server.py</a> 373 388 <a href="listings/pb/trap_client.py" class="py-listing">trap_client.py</a> … … 396 411 know which local class ought to be used to create an instance that 397 412 corresponds to the remote object<!-- eat breaking space 398 413 399 --><span class="footnote"><p>The naive approach of simply doing <code>import 400 SomeClass</code> to match a remote caller who claims to have an object of 401 type <q>SomeClass</q> could have nasty consequences for some modules that do 402 significant operations in their <code>__init__</code> methods (think 403 <code>telnetlib.Telnet(host='localhost', port='chargen')</code>, or even 404 more powerful classes that you have available in your server program). 405 Allowing a remote entity to create arbitrary classes in your namespace is 406 nearly equivalent to allowing them to run arbitrary code.</p> 414 --><span class="footnote"><p>The naive approach of simply 415 doing <code>import SomeClass</code> to match a remote caller who 416 claims to have an object of type <q>SomeClass</q> could have nasty 417 consequences for some modules that do significant operations in 418 their <code>__init__</code> methods 419 (think <code>telnetlib.Telnet(host='localhost', 420 port='chargen')</code>, or even more powerful classes that you have 421 available in your server program). Allowing a remote entity to create 422 arbitrary classes in your namespace is nearly equivalent to allowing 423 them to run arbitrary code.</p> 407 424 408 425 <p>The <code class="API" base="twisted.spread">pb.InsecureJelly</code> 409 exception arises because the class being sent over the wire has not been 410 registered with the serialization layer (known as <code class="API" 411 base="twisted.spread">jelly</code>). The easiest way to make it possible to 412 copy entire class instances over the wire is to have them inherit from <code 413 class="API" base="twisted.spread">pb.Copyable</code>, and then to use 414 <code>setUnjellyableForClass(remoteClass, localClass)</code> on the 415 receiving side. See <a href="pb-copyable.xhtml">Passing Complex Types</a> 416 for an example.</p></span>. 417 418 The receiving end of the connection gets to decide what to accept and what 419 to reject. It indicates its disapproval by raising a <code class="API" 420 base="twisted.spread">pb.InsecureJelly</code> exception. Because it occurs 421 at the remote end, the exception is returned to the caller asynchronously, 422 so an <code>errback</code> handler for the associated <code>Deferred</code> 423 is run. That errback receives a <code>Failure</code> which wraps the 424 <code>InsecureJelly</code>.</p> 425 426 427 <p>Remember that <code>trap</code> re-raises exceptions that it wasn't asked 428 to look for. You can only check for one set of exceptions per errback 429 handler: all others must be checked in a subsequent handler. 430 <code>check_MyException</code> shows how multiple kinds of exceptions can be 431 checked in a single errback: give a list of exception types to 432 <code>trap</code>, and it will return the matching member. In this case, the 433 kinds of exceptions we are checking for (<code>MyException</code> and 434 <code>MyOtherException</code>) may be raised by the remote end: they inherit 435 from <code class="API" base="twisted.spread">pb.Error</code>.</p> 436 437 <p>The handler can return <code>None</code> to terminate processing of the 438 errback chain (to be precise, it switches to the callback that follows the 439 errback; if there is no callback then processing terminates). It is a good 440 idea to put an errback that will catch everything (no <code>trap</code> 441 tests, no possible chance of raising more exceptions, always returns 442 <code>None</code>) at the end of the chain. Just as with regular <code>try: 443 except:</code> handlers, you need to think carefully about ways in which 444 your errback handlers could themselves raise exceptions. The extra 445 importance in an asynchronous environment is that an exception that falls 446 off the end of the <code>Deferred</code> will not be signalled until that 447 <code>Deferred</code> goes out of scope, and at that point may only cause a 448 log message (which could even be thrown away if <code class="API" 449 base="twisted.python">log.startLogging</code> is not used to point it at 450 stdout or a log file). In contrast, a synchronous exception that is not 451 handled by any other <code>except:</code> block will very visibly terminate 452 the program immediately with a noisy stack trace.</p> 426 exception arises because the class being sent over the wire has not 427 been registered with the serialization layer (known 428 as <code class="API" base="twisted.spread">jelly</code>). The easiest 429 way to make it possible to copy entire class instances over the wire 430 is to have them inherit from <code class="API" 431 base="twisted.spread">pb.Copyable</code>, and then to 432 use <code>setUnjellyableForClass(remoteClass, localClass)</code> on 433 the receiving side. See <a href="pb-copyable.xhtml">Passing Complex 434 Types</a> for an example.</p></span>. 435 436 The receiving end of the connection gets to decide what to accept and 437 what to reject. It indicates its disapproval by raising 438 a <code class="API" base="twisted.spread">pb.InsecureJelly</code> 439 exception. Because it occurs at the remote end, the exception is 440 returned to the caller asynchronously, so an <code>errback</code> 441 handler for the associated <code>Deferred</code> is run. That errback 442 receives a <code>Failure</code> which wraps 443 the <code>InsecureJelly</code>.</p> 444 445 446 <p>Remember that <code>trap</code> re-raises exceptions that it wasn't 447 asked to look for. You can only check for one set of exceptions per 448 errback handler: all others must be checked in a subsequent 449 handler. <code>check_MyException</code> shows how multiple kinds of 450 exceptions can be checked in a single errback: give a list of 451 exception types to <code>trap</code>, and it will return the matching 452 member. In this case, the kinds of exceptions we are checking for 453 (<code>MyException</code> and <code>MyOtherException</code>) may be 454 raised by the remote end: they inherit from <code class="API" 455 base="twisted.spread">pb.Error</code>.</p> 456 457 <p>The handler can return <code>None</code> to terminate processing of 458 the errback chain (to be precise, it switches to the callback that 459 follows the errback; if there is no callback then processing 460 terminates). It is a good idea to put an errback that will catch 461 everything (no <code>trap</code> tests, no possible chance of raising 462 more exceptions, always returns <code>None</code>) at the end of the 463 chain. Just as with regular <code>try: except:</code> handlers, you 464 need to think carefully about ways in which your errback handlers 465 could themselves raise exceptions. The extra importance in an 466 asynchronous environment is that an exception that falls off the end 467 of the <code>Deferred</code> will not be signalled until 468 that <code>Deferred</code> goes out of scope, and at that point may 469 only cause a log message (which could even be thrown away 470 if <code class="API" base="twisted.python">log.startLogging</code> is 471 not used to point it at stdout or a log file). In contrast, a 472 synchronous exception that is not handled by any 473 other <code>except:</code> block will very visibly terminate the 474 program immediately with a noisy stack trace.</p> 453 475 454 476 <p><code>callFour</code> shows another kind of exception that can occur 455 477 while using <code>callRemote</code>: <code class="API" … … 460 482 synchronous <code>try: except pb.DeadReferenceError</code> block. </p> 461 483 462 484 <p>Yet another kind that can occur is a <code class="API" 463 base="twisted.spread">pb.PBConnectionLost</code> exception. This occurs 464 (asynchronously) if the connection was lost while you were waiting for a 465 <code>callRemote</code> call to complete. When the line goes dead, all 466 pending requests are terminated with this exception. Note that you have no 467 way of knowing whether the request made it to the other end or not, nor how 468 far along in processing it they had managed before the connection was 469 lost. XXX: explain transaction semantics, find a decent reference.</p> 485 base="twisted.spread">pb.PBConnectionLost</code> exception. This 486 occurs (asynchronously) if the connection was lost while you were 487 waiting for a <code>callRemote</code> call to complete. When the line 488 goes dead, all pending requests are terminated with this 489 exception. Note that you have no way of knowing whether the request 490 made it to the other end or not, nor how far along in processing it 491 they had managed before the connection was lost. XXX: explain 492 transaction semantics, find a decent reference.</p> 470 493 471 494 </body> </html>
